Ciclo de vida de la actividad
Las actividades son un bloque de creación fundamental de las aplicaciones Android y pueden existir en varios estados diferentes. El ciclo de vida de la actividad comienza con la creación de instancias y termina con la destrucción, e incluye muchos estados entre ellos. Cuando una actividad cambia de estado, se llama al método de evento de ciclo de vida adecuado, notificando a la actividad del cambio de estado inmediato y permitiéndole ejecutar código para adaptarse a ese cambio. En este artículo se examina el ciclo de vida de las actividades y se explica la responsabilidad que tiene una actividad durante cada uno de estos cambios de estado para ser una aplicación confiable y que se comporte correctamente.
Información general sobre el ciclo de vida de la actividad
Las actividades son un concepto de programación inusual específico de Android. En el desarrollo de aplicaciones tradicional, normalmente hay un método main estático, que se ejecuta para iniciar la aplicación. Sin embargo, con Android, las cosas son diferentes, las aplicaciones Android se pueden iniciar a través de cualquier actividad registrada dentro de una aplicación. En la práctica, la mayoría de las aplicaciones solo tendrán una actividad específica que se especifica como punto de entrada de la aplicación. Sin embargo, si una aplicación se bloquea o el sistema operativo la finaliza, el sistema operativo puede intentar reiniciar la aplicación en la última actividad abierta o en cualquier otro lugar dentro de la pila de actividad anterior. Además, el sistema operativo puede pausar las actividades cuando no están activas y reclamarlas si tiene poca memoria. Debe tenerse en cuenta detenidamente para permitir que la aplicación restaure correctamente su estado en caso de que se reinicie una actividad, especialmente si esa actividad depende de los datos de actividades anteriores.
El ciclo de vida de la actividad se implementa como una colección de métodos a los que llama el sistema operativo a lo largo del ciclo de vida de una actividad. Estos métodos permiten a los desarrolladores implementar la funcionalidad necesaria para satisfacer los requisitos de administración de recursos y estados de sus aplicaciones.
Es muy importante que el desarrollador de aplicaciones analice los requisitos de cada actividad para determinar qué métodos expuestos por el ciclo de vida de la actividad deben implementarse. Si no lo hace, puede producir inestabilidad en la aplicación, bloqueos, un exceso de recursos e incluso la inestabilidad del sistema operativo subyacente.
En este capítulo se examina el ciclo de vida de la actividad en detalle, incluidos:
- Estados de actividad
- Métodos de ciclo de vida
- Conservación del estado de una aplicación
En esta sección también se incluye un tutorial que proporciona ejemplos prácticos sobre cómo guardar el estado de forma eficaz durante el ciclo de vida de la actividad. Al final de este capítulo, debe comprender el ciclo de vida de la actividad y cómo admitirlo en una aplicación Android.
Ciclo de vida de la actividad
El ciclo de vida de la actividad de Android consta de una colección de métodos expuestos dentro de la clase Activity que proporcionan al desarrollador un marco de administración de recursos. Este marco permite a los desarrolladores cumplir los requisitos de administración de estado únicos de cada actividad dentro de una aplicación y administrar correctamente la administración de recursos.
Estados de actividad
El sistema operativo Android aborda las actividades en función de su estado. Esto ayuda a Android a identificar las actividades que ya no están en uso, lo que permite que el sistema operativo reclame memoria y recursos. En el diagrama siguiente se muestran los estados por los que puede pasar una actividad durante su duración:
Estos estados se pueden dividir en 4 grupos principales como se indica a continuación:
Activa o En ejecución: las actividades se consideran activas o en ejecución si están en primer plano, también conocido como la parte superior de la pila de actividad. Esto se considera la actividad de prioridad más alta en Android y, como tal, solo la interrumpirá el sistema operativo en situaciones extremas, como si la actividad intenta usar más memoria de la que está disponible en el dispositivo, ya que esto podría hacer que la interfaz de usuario deje de responder.
Pausada: cuando el dispositivo entra en suspensión, o una actividad sigue visible pero parcialmente oculta por una actividad nueva, no de tamaño completo o transparente, la actividad se considera pausada. Las actividades en pausa siguen activas, es decir, mantienen toda la información de estado y miembro, y permanecen asociadas al administrador de ventanas. Se considera la segunda actividad de prioridad más alta en Android y, como tal, solo la interrumpirá el sistema operativo si al acabar esta actividad se cumplirán los requisitos de recursos necesarios para mantener la actividad activa o en ejecución estable y con capacidad de respuesta.
Detenida/En segundo plano: las actividades que están completamente ocultas por otra actividad se consideran detenidas o en segundo plano. Las actividades detenidas siguen intentando conservar su estado y su información de miembro durante el mayor tiempo posible, pero las actividades detenidas se consideran la prioridad más baja de los tres estados y, por lo tanto, el sistema operativo elimina primero las actividades en este estado para satisfacer los requisitos de recursos de las actividades de prioridad más alta.
Reiniciada: es posible que Android quite de la memoria una actividad que esté en cualquier lugar desde una pausa hasta que se detenga en el ciclo de vida. Si el usuario vuelve a la actividad, debe reiniciarse, restaurarse a su estado guardado previamente y, a continuación, mostrarse al usuario.
Actividad de recreación como respuesta a los cambios de configuración
Para complicar más las cosas, Android añade también los llamados Cambios de Configuración. Los cambios de configuración son ciclos rápidos de destrucción o recreación de actividades que se producen cuando cambia la configuración de una actividad, como cuando se gira el dispositivo (y la actividad necesita volver a crearse en modo horizontal o vertical), cuando se muestra el teclado (y la actividad se presenta con la oportunidad de cambiar su tamaño), o cuando el dispositivo se coloca en una base, entre otros.
Los cambios de configuración siguen provocando los mismos cambios de estado de actividad que se producirían durante la detención y el reinicio de una actividad. Sin embargo, para asegurarse de que una aplicación tiene capacidad de respuesta y funciona bien durante los cambios de configuración, es importante que se controle lo más rápido posible. Por este problema, Android tiene una API específica que se puede usar para conservar el estado durante los cambios de configuración. Trataremos esto más adelante en la sección Administración del estado a lo largo del ciclo de vida.
Métodos de ciclo de vida de actividad
El Android SDK y, por extensión, el marco de Xamarin.Android proporcionan un modelo eficaz para administrar el estado de las actividades dentro de una aplicación. Cuando cambia el estado de una actividad, el sistema operativo notifica a la actividad, que llama a métodos específicos de esa actividad. En el diagrama siguiente se muestran estos métodos en relación con el ciclo de vida de la actividad:
Como desarrollador, puede controlar los cambios de estado invalidando estos métodos dentro de una actividad. Sin embargo, es importante tener en cuenta que se llama a todos los métodos de ciclo de vida en el subproceso de la interfaz de usuario e impedirá que el sistema operativo realice el siguiente trabajo de la interfaz de usuario, como ocultar la actividad actual, mostrar una nueva actividad, etc. Por lo tanto, el código de estos métodos debe ser lo más breve posible para que una aplicación funcione de forma fluida. Las tareas de ejecución larga se deben ejecutar en un subproceso en segundo plano.
Examinemos cada uno de estos métodos de ciclo de vida y su uso:
OnCreate
OnCreate es el primer método al que se llamará cuando se crea una actividad.
OnCreate
siempre se invalida para realizar las inicializaciones de inicio que pueda requerir una actividad como:
- Creación de vistas
- Inicialización de variables
- Enlace de datos estáticos a listas
OnCreate
toma un parámetro Bundle, que es un diccionario para almacenar y pasar información de estado y objetos entre actividades. Si el parámetro no es null, esto indica que la actividad se está reiniciando y debe restaurar su estado de la instancia anterior. En el código siguiente se muestra cómo recuperar valores del parámetro:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
string intentString;
bool intentBool;
if (bundle != null)
{
intentString = bundle.GetString("myString");
intentBool = bundle.GetBoolean("myBool");
}
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
}
Una vez que OnCreate
haya terminado, Android llamará a OnStart
.
OnStart
El sistema siempre llama a OnStart una vez que OnCreate
haya finalizado. Las actividades pueden invalidar este método si necesitan realizar tareas específicas justo antes de que una actividad se vuelva visible, como actualizar los valores actuales de las vistas dentro de la actividad. Android llamará inmediatamente a OnResume
después de este método.
OnResume
El sistema llama a OnResume cuando la actividad está lista para empezar a interactuar con el usuario. Las actividades deben invalidar este método para realizar tareas como:
- Aumentar las velocidades de fotogramas (una tarea común en el desarrollo de juegos)
- Inicio de animaciones
- Escucha de actualizaciones de GPS
- Mostrar las alertas o cuadros de diálogo pertinentes
- Conexión de controladores de eventos externos
Por ejemplo, el siguiente fragmento de código muestra cómo inicializar la cámara:
protected override void OnResume()
{
base.OnResume(); // Always call the superclass first.
if (_camera==null)
{
// Do camera initializations here
}
}
OnResume
es importante porque cualquier operación que se realiza en OnPause
debe deshacerse en OnResume
, ya que es el único método de ciclo de vida que se garantiza que se ejecute después de OnPause
al devolver la actividad de vuelta a la vida.
OnPause
Se llama a OnPause cuando el sistema está a punto de colocar la actividad en segundo plano o cuando la actividad se oculta parcialmente. Las actividades deben invalidar este método si necesitan:
Confirmar cambios no guardados en datos persistentes
Destruir o limpiar otros objetos que consumen recursos
Aumentar las velocidades de fotogramas y pausar animaciones
Anular el registro de controladores de eventos externos o controladores de notificaciones (es decir, los que están asociados a un servicio). Esto debe hacerse para evitar pérdidas de memoria de actividad.
Del mismo modo, si la actividad ha mostrado diálogos o alertas, deben limpiarse con el método
.Dismiss()
.
Por ejemplo, el siguiente fragmento de código liberará la cámara, ya que la actividad no puede hacer uso de ella mientras está en pausa:
protected override void OnPause()
{
base.OnPause(); // Always call the superclass first
// Release the camera as other activities might need it
if (_camera != null)
{
_camera.Release();
_camera = null;
}
}
Hay dos métodos de ciclo de vida posibles a los que se llamará después de OnPause
:
OnResume
se llamará si se va a devolver la actividad al primer plano.OnStop
se llamará si la actividad se coloca en segundo plano.
OnStop
Se llama a OnStop cuando la actividad ya no es visible para el usuario. Esto sucede cuando se produce una de las siguientes situaciones:
- Se está iniciando una nueva actividad que cubre esta actividad.
- Una actividad existente está en primer plano.
- La actividad se está interrumpiendo.
Es posible que no siempre se llame a OnStop
en situaciones de memoria baja, como cuando Android necesita más recursos y no puede realizar en segundo plano correctamente la actividad. Por este motivo, es mejor no confiar en que se llame a OnStop
al preparar una actividad para la interrupción. Los métodos de ciclo de vida siguientes a los que se puede llamar después de este serán OnDestroy
si la actividad va a desaparecer o OnRestart
si la actividad vuelve a interactuar con el usuario.
OnDestroy
OnDestroy es el método final al que se llama en una instancia de Activity antes de que se destruya y se quite completamente de la memoria. En situaciones extremas, Android puede eliminar el proceso de aplicación que hospeda la actividad, lo que provocará que no se invoque OnDestroy
. La mayoría de las actividades no implementarán este método porque la mayoría de las tareas de limpieza y apagado se han realizado en los métodos OnPause
y OnStop
. Normalmente, el método OnDestroy
se invalida para limpiar las tareas de larga duración que podrían filtrar recursos. Un ejemplo de esto podría ser subprocesos en segundo plano que se iniciaron en OnCreate
.
No se llamará a ningún método de ciclo de vida después de destruir la actividad.
OnRestart
Se llama a OnRestart después de que se haya detenido la actividad, antes de que se vuelva a iniciar. Un buen ejemplo de esto sería cuando el usuario presiona el botón inicio mientras está en una actividad de la aplicación. Cuando esto sucede se llama a los métodos OnPause
, y luego a OnStop
, y la actividad se mueve a segundo plano, pero no se destruye. Si el usuario fuera a restaurar la aplicación mediante el administrador de tareas o una aplicación similar, Android llamará al método OnRestart
de la actividad.
No hay ninguna guía general para qué tipo de lógica se debe implementar en OnRestart
. Esto se debe a que OnStart
siempre se invoca independientemente de si se crea o se reinicia la actividad, por lo que los recursos necesarios para la actividad se deben inicializar en OnStart
, en lugar de OnRestart
.
El siguiente método de ciclo de vida llamado después de OnRestart
será OnStart
.
Atrás frente a Página principal
Muchos dispositivos Android tienen dos botones distintos: un botón "Atrás" y un botón "Inicio". Puede ver un ejemplo de esto en la captura de pantalla siguiente de Android 4.0.3:
Hay una diferencia sutil entre los dos botones, aunque parezcan tener el mismo efecto de poner una aplicación en segundo plano. Cuando un usuario hace clic en botón Atrás, le dice a Android que ha terminado con la actividad. Android destruirá la actividad. Por el contrario, cuando el usuario hace clic en el botón Inicio, la actividad simplemente se coloca en segundo plano: Android no finalizará la actividad.
Administración del estado a lo largo del ciclo de vida
Cuando se detiene o destruye una actividad, el sistema ofrece la oportunidad de guardar el estado de la actividad para su posterior rehidratación. Este estado guardado se conoce como estado de instancia. Android proporciona tres opciones para almacenar el estado de la instancia durante el ciclo de vida de la actividad:
Almacenar valores primitivos en un
Dictionary
conocido como Bundle que Android usará para guardar el estado.Crear una clase personalizada que contendrán valores complejos, como mapas de bits. Android usará esta clase personalizada para guardar el estado.
Evitar el ciclo de vida de cambio de configuración y asumir la responsabilidad total de mantener el estado en la actividad.
En esta guía se tratan las dos primeras opciones.
Estado Bundle
La opción principal para guardar el estado de la instancia es usar un objeto de diccionario de clave-valor conocido como Bundle.
Recuerde que, cuando se crea una actividad, al método OnCreate
se le pasa una agrupación como parámetro, esta agrupación se puede usar para restaurar el estado de la instancia. No se recomienda usar una agrupación para datos más complejos que no se serializarán de forma rápida o sencilla en pares clave-valor (como mapas de bits). En su lugar, se debe usar para valores simples como cadenas.
Una actividad proporciona métodos para ayudar a guardar y recuperar el estado de instancia en la agrupación:
OnSaveInstanceState: Android invoca esto cuando se destruye la actividad. Las actividades pueden implementar este método si necesitan conservar los elementos de estado clave-valor.
OnRestoreInstanceState: se llama una vez finalizado el método
OnCreate
y proporciona otra oportunidad para que una actividad restaure su estado una vez completada la inicialización.
El siguiente diagrama ilustra cómo se relacionan estos componentes:
OnSaveInstanceState
Se llamará a OnSaveInstanceState cuando se detenga la actividad. Recibirá un parámetro de agrupación en el que la actividad puede almacenar su estado. Cuando un dispositivo experimenta un cambio de configuración, una actividad puede usar el objeto Bundle
que se pasa para conservar el estado actividad invalidando OnSaveInstanceState
. Por ejemplo, suponga el siguiente código:
int c;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
this.SetContentView (Resource.Layout.SimpleStateView);
var output = this.FindViewById<TextView> (Resource.Id.outputText);
if (bundle != null) {
c = bundle.GetInt ("counter", -1);
} else {
c = -1;
}
output.Text = c.ToString ();
var incrementCounter = this.FindViewById<Button> (Resource.Id.incrementCounter);
incrementCounter.Click += (s,e) => {
output.Text = (++c).ToString();
};
}
El código anterior incrementa un entero denominado c
cuando se hace clic en un botón denominado incrementCounter
y se muestra el resultado en un objeto TextView
denominado output
. Cuando se produce un cambio de configuración (por ejemplo, cuando se gira el dispositivo), el código anterior perdería el valor de c
porque bundle
sería null
, como se muestra en la ilustración siguiente:
Para conservar el valor de c
en este ejemplo, la actividad puede invalidar OnSaveInstanceState
y guardar el valor en la agrupación, como se muestra a continuación:
protected override void OnSaveInstanceState (Bundle outState)
{
outState.PutInt ("counter", c);
base.OnSaveInstanceState (outState);
}
Ahora, cuando el dispositivo gira a una nueva orientación, el entero se guarda en la agrupación y se recupera con la línea:
c = bundle.GetInt ("counter", -1);
Nota:
Es importante llamar siempre a la implementación base de OnSaveInstanceState
para que también se pueda guardar el estado de la jerarquía de vistas.
Ver estado
La invalidación de OnSaveInstanceState
es un mecanismo adecuado para guardar datos transitorios en una actividad en los cambios de orientación, como el contador del ejemplo anterior. Sin embargo, la implementación predeterminada de OnSaveInstanceState
se encargará de guardar datos transitorios en la interfaz de usuario para cada vista, siempre que cada vista tenga asignado un identificador. Por ejemplo, supongamos que una aplicación tiene un elemento EditText
definido en XML de la siguiente manera:
<EditText android:id="@+id/myText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
Puesto que el control EditText
tiene id
asignado, cuando el usuario escribe algunos datos y gira el dispositivo, los datos se siguen mostrando, como se muestra a continuación:
OnRestoreInstanceState
Se llamará a OnRestoreInstanceState después de OnStart
. Proporciona una actividad la oportunidad de restaurar cualquier estado que se guardó anteriormente en un Bundle durante el anterior OnSaveInstanceState
. Esta es la misma agrupación que se proporciona a OnCreate
, sin embargo.
En el código siguiente se muestra cómo se puede restaurar el estado en OnRestoreInstanceState
:
protected override void OnRestoreInstanceState(Bundle savedState)
{
base.OnRestoreInstanceState(savedState);
var myString = savedState.GetString("myString");
var myBool = savedState.GetBoolean("myBool");
}
Este método existe para proporcionar cierta flexibilidad en torno al momento en que se debe restaurar el estado. A veces es más adecuado esperar hasta que se realizan todas las inicializaciones antes de restaurar el estado de la instancia. Además, es posible que una subclase de una actividad existente solo desee restaurar determinados valores del estado de instancia. En muchos casos, no es necesario invalidar OnRestoreInstanceState
, ya que la mayoría de las actividades pueden restaurar el estado mediante la agrupación proporcionada a OnCreate
.
Para obtener un ejemplo de cómo guardar el estado mediante Bundle
, consulte el Tutorial: guardado del estado de actividad.
Limitaciones de Bundle
Aunque OnSaveInstanceState
facilita el guardado de datos transitorios, tiene algunas limitaciones:
No se llama en todos los casos. Por ejemplo, al presionar Inicio o Atrás para salir de una actividad, no hará que se llame a
OnSaveInstanceState
.La agrupación pasada a
OnSaveInstanceState
no está diseñada para objetos grandes, como imágenes. En el caso de objetos grandes, es preferible guardar el objeto de OnRetainNonConfigurationInstance, como se describe a continuación.Los datos guardados mediante la agrupación se serializan, lo que puede provocar retrasos.
El estado de agrupación es útil para datos simples que no usan mucha memoria, mientras que los datos de instancia que no son de configuración son útiles para datos más complejos o datos que son costosos de recuperar, como desde una llamada de servicio web o una consulta de base de datos complicada. Los datos de instancia que no son de configuración se guardan en un objeto según sea necesario. En la sección siguiente se presenta OnRetainNonConfigurationInstance
como una manera de conservar tipos de datos más complejos mediante cambios de configuración.
Conservación de datos complejos
Además de conservar los datos de la agrupación, Android también admite guardar datos reemplazando OnRetainNonConfigurationInstance y devolviendo una instancia de Java.Lang.Object
que contiene los datos que se van a conservar. Hay dos ventajas principales de usar OnRetainNonConfigurationInstance
para guardar el estado:
El objeto devuelto de
OnRetainNonConfigurationInstance
funciona bien con tipos de datos más grandes y complejos porque la memoria conserva este objeto.Se llama al método
OnRetainNonConfigurationInstance
a petición y solo cuando es necesario. Esto es más económico que usar una caché manual.
El uso de OnRetainNonConfigurationInstance
es adecuado para escenarios en los que es costoso recuperar los datos varias veces, como en llamadas de servicio web. Por ejemplo, considere el siguiente código que busca en Twitter:
public class NonConfigInstanceActivity : ListActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SearchTwitter ("xamarin");
}
public void SearchTwitter (string text)
{
string searchUrl = String.Format("http://search.twitter.com/search.json?" + "q={0}&rpp=10&include_entities=false&" + "result_type=mixed", text);
var httpReq = (HttpWebRequest)HttpWebRequest.Create (new Uri (searchUrl));
httpReq.BeginGetResponse (new AsyncCallback (ResponseCallback), httpReq);
}
void ResponseCallback (IAsyncResult ar)
{
var httpReq = (HttpWebRequest)ar.AsyncState;
using (var httpRes = (HttpWebResponse)httpReq.EndGetResponse (ar)) {
ParseResults (httpRes);
}
}
void ParseResults (HttpWebResponse httpRes)
{
var s = httpRes.GetResponseStream ();
var j = (JsonObject)JsonObject.Load (s);
var results = (from result in (JsonArray)j ["results"] let jResult = result as JsonObject select jResult ["text"].ToString ()).ToArray ();
RunOnUiThread (() => {
PopulateTweetList (results);
});
}
void PopulateTweetList (string[] results)
{
ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
}
}
Este código recupera los resultados de la web con formato JSON, los analiza y, a continuación, presenta los resultados en una lista, como se muestra en la captura de pantalla siguiente:
Cuando se produce un cambio de configuración (por ejemplo, cuando se gira un dispositivo), el código repite el proceso. Para reutilizar los resultados recuperados originalmente y no provocar llamadas de red innecesarias y redundantes, podemos usar OnRetainNonconfigurationInstance
para guardar los resultados, como se muestra a continuación:
public class NonConfigInstanceActivity : ListActivity
{
TweetListWrapper _savedInstance;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
var tweetsWrapper = LastNonConfigurationInstance as TweetListWrapper;
if (tweetsWrapper != null) {
PopulateTweetList (tweetsWrapper.Tweets);
} else {
SearchTwitter ("xamarin");
}
public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
base.OnRetainNonConfigurationInstance ();
return _savedInstance;
}
...
void PopulateTweetList (string[] results)
{
ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
_savedInstance = new TweetListWrapper{Tweets=results};
}
}
Ahora, cuando se gira el dispositivo, los resultados originales se recuperan de la propiedad LastNonConfiguartionInstance
. En este ejemplo, los resultados constan de un elemento string[]
que contiene tweets. Puesto que OnRetainNonConfigurationInstance
requiere que se devuelva Java.Lang.Object
, string[]
se ajusta en una clase y una subclase Java.Lang.Object
, como se muestra a continuación:
class TweetListWrapper : Java.Lang.Object
{
public string[] Tweets { get; set; }
}
Por ejemplo, al intentar usar TextView
como objeto devuelto de OnRetainNonConfigurationInstance
se filtrará la actividad, como se muestra en el código siguiente:
TextView _textView;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
var tv = LastNonConfigurationInstance as TextViewWrapper;
if(tv != null) {
_textView = tv;
var parent = _textView.Parent as FrameLayout;
parent.RemoveView(_textView);
} else {
_textView = new TextView (this);
_textView.Text = "This will leak.";
}
SetContentView (_textView);
}
public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
base.OnRetainNonConfigurationInstance ();
return _textView;
}
En esta sección, hemos aprendido a conservar datos de estado simples con Bundle
y a conservar tipos de datos más complejos con OnRetainNonConfigurationInstance
.
Resumen
El ciclo de vida de la actividad de Android proporciona un marco eficaz para la administración de estados de las actividades dentro de una aplicación, pero puede ser difícil de entender e implementar. En este capítulo se presentan los distintos estados por los que puede pasar una actividad durante su duración, así como los métodos de ciclo de vida asociados a esos estados. A continuación, se proporcionó orientación sobre qué tipo de lógica se debe realizar en cada uno de estos métodos.