1. Benvinguts
Aquest laboratori pràctic forma part de la Unitat 1: Iniciació al curs Fonaments per a desenvolupadors d'Android (versió 2). Treureu el màxim profit d'aquest curs si treballeu els laboratoris de codificació en seqüència:
- Per obtenir la llista completa de codelabs del curs, vegeu Codelabs for Android Developer Fundamentals (V2).
- Per obtenir més informació sobre el curs, inclosos els enllaços a tots els capítols conceptuals, aplicacions i diapositives, consulteu Fonaments per a desenvolupadors d'Android (versió 2).
Introducció
En aquesta pràctica aprendràs més sobre el cicle de vida de l'activitat. El cicle de vida és el conjunt d'estats en què pot estar una activitat durant tota la seva vida útil, des del moment en què es crea fins al moment en què es destrueix i el sistema recupera els seus recursos. A mesura que un usuari navega entre les activitats de la vostra aplicació (així com dins i fora de la vostra aplicació), les activitats passen entre diferents estats en els seus cicles de vida.
Cada etapa del cicle de vida d'una activitat té un mètode de devolució de trucada corresponent: onCreate(), onStart(), onPause(), etc. Quan una activitat canvia d'estat, s'invoca el mètode de devolució de trucada associat. Ja heu vist un d'aquests mètodes: onCreate(). En anul·lar qualsevol dels mètodes de devolució de trucada del cicle de vida a les classes d'activitat, podeu canviar el comportament predeterminat de l'activitat en resposta a les accions de l'usuari o del sistema.
L'estat de l'activitat també pot canviar en resposta als canvis de configuració del dispositiu, per exemple, quan l'usuari gira el dispositiu de vertical a horitzontal. Quan es produeixen aquests canvis de configuració, l'activitat es destrueix i es recrea en el seu estat predeterminat i l'usuari pot perdre la informació que ha introduït a l'activitat. Per evitar confondre els usuaris, és important que desenvolupeu la vostra aplicació per evitar pèrdues de dades inesperades. Més endavant, en aquesta pràctica, experimenteu amb els canvis de configuració i apreneu a preservar l'estat d'una activitat en resposta als canvis de configuració del dispositiu i altres esdeveniments del cicle de vida de l'activitat.
En aquesta pràctica, afegiu declaracions de registre a l'aplicació TwoActivities i observeu els canvis del cicle de vida de l'activitat mentre feu servir l'aplicació. A continuació, comenceu a treballar amb aquests canvis i a explorar com gestionar l'entrada de l'usuari en aquestes condicions.
Requisits previs
Hauries de ser capaç de:
- Creeu i executeu un projecte d'aplicació a Android Studio .
- Afegiu declaracions de registre a la vostra aplicació i visualitzeu aquests registres al panell de Logcat.
- Comprendre i treballar amb una activitat i una intenció, i sentir-se còmode interactuant amb ells.
El que aprendràs
- Com funciona el cicle de vida de l'activitat.
- Quan una activitat comença, s'atura, s'atura i es destrueix.
- Sobre els mètodes de devolució de trucada del cicle de vida associats als canvis d'activitat.
- L'efecte de les accions (com ara els canvis de configuració) que poden provocar esdeveniments del cicle de vida de l'activitat.
- Com conservar l'estat de l'activitat durant els esdeveniments del cicle de vida.
Què faràs
- Afegiu codi a l'aplicació TwoActivities de la pràctica anterior per implementar les diverses devolucions de trucada del cicle de vida de l'activitat per incloure declaracions de registre.
- Observeu els canvis d'estat a mesura que s'executa la vostra aplicació i mentre interactueu amb cada activitat de la vostra aplicació.
- Modifiqueu la vostra aplicació per mantenir l'estat d'instància d'una activitat que es recrea de manera inesperada en resposta al comportament de l'usuari o al canvi de configuració al dispositiu.
2. Visió general de l'aplicació
En aquesta pràctica s'afegeix a l'aplicació TwoActivities . L'aplicació té un aspecte i un comportament aproximadament igual que a l'últim laboratori de codificació. Conté dues implementacions d'Activity i ofereix a l'usuari la possibilitat d'enviar entre elles. Els canvis que feu a l'aplicació en aquesta pràctica no afectaran el seu comportament visible de l'usuari.
3. 3. Tasca 1: Afegiu devolucions de trucada del cicle de vida a TwoActivities
En aquesta tasca implementareu tots els mètodes de devolució del cicle de vida de l'activitat per imprimir missatges al logcat quan s'invoquin aquests mètodes. Aquests missatges de registre us permetran veure quan el cicle de vida de l'activitat canvia d'estat i com aquests canvis d'estat del cicle de vida afecten la vostra aplicació mentre s'executa.
1.1 (Opcional) Copia el projecte TwoActivities
Per a les tasques d'aquesta pràctica, modificareu el projecte de TwoActivities existent que heu creat a l'última pràctica. Si preferiu mantenir intacte el projecte anterior de TwoActivities, seguiu els passos de l'Apèndix: Utilitats per fer una còpia del projecte.
1.2 Implementar devolucions de trucada a MainActivity
- Obriu el projecte TwoActivities a Android Studio i obriu MainActivity al panell Projecte > Android.
- Al mètode onCreate(), afegiu les instruccions de registre següents:
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
- Afegiu una substitució per a la devolució de trucada onStart(), amb una declaració al registre d'aquest esdeveniment:
@Override
public void onStart(){
super.onStart();
Log.d(LOG_TAG, "onStart");
}
Per obtenir una drecera, seleccioneu Codi > Anul·lació de mètodes a Android Studio. Apareix un diàleg amb tots els mètodes possibles que podeu substituir a la vostra classe. Si escolliu un o més mètodes de devolució de trucada de la llista, s'insereix una plantilla completa per a aquests mètodes, inclosa la trucada necessària a la superclasse.
- Utilitzeu el mètode onStart() com a plantilla per implementar les devolucions de trucada del cicle de vida onPause(), onRestart(), onResume(), onStop() i onDestroy().
Tots els mètodes de devolució de trucada tenen les mateixes signatures (excepte el nom). Si copieu i enganxeu onStart() per crear aquests altres mètodes de devolució de trucada, no us oblideu d'actualitzar el contingut per trucar al mètode correcte a la superclasse i registrar el mètode correcte.
- Executeu la vostra aplicació.
- Feu clic a la pestanya Logcat a la part inferior d'Android Studio per mostrar el panell Logcat. Hauríeu de veure tres missatges de registre que mostren els tres estats del cicle de vida pels quals ha transigut l'activitat quan va començar:
D/MainActivity: -------
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onResume
1.3 Implementar devolucions de trucada del cicle de vida a SecondActivity
Ara que heu implementat els mètodes de devolució del cicle de vida per a MainActivity, feu el mateix per a SecondActivity.
- Obriu SecondActivity.
- A la part superior de la classe, afegiu una constant per a la variable LOG_TAG:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
- Afegiu les devolucions de trucada del cicle de vida i les declaracions de registre a la segona activitat. (Podeu copiar i enganxar els mètodes de devolució de trucada des de MainActivity.)
- Afegiu una instrucció de registre al mètode returnReply() just abans del mètode finish():
Log.d(LOG_TAG, "End SecondActivity");
1.4 Observeu el registre mentre s'executa l'aplicació**
- Executeu la vostra aplicació.
- Feu clic a la pestanya Logcat a la part inferior d'Android Studio per mostrar el panell Logcat.
- Introduïu Activitat al quadre de cerca. El logcat d'Android pot ser molt llarg i desordenat. Com que la variable LOG_TAG de cada classe conté les paraules MainActivity o SecondActivity, aquesta paraula clau us permet filtrar el registre només per les coses que us interessen.
Experimenteu amb la vostra aplicació i tingueu en compte que els esdeveniments del cicle de vida que es produeixen en resposta a diferents accions. En particular, proveu aquestes coses:
- Utilitza l'aplicació amb normalitat (envia un missatge, respon amb un altre missatge).
- Feu servir el botó Enrere per tornar de la segona activitat a l'activitat principal.
- Utilitzeu la fletxa amunt de la barra de l'aplicació per tornar de la segona activitat a l'activitat principal.
- Gireu el dispositiu tant a l'activitat principal com a la segona en diferents moments de la vostra aplicació i observeu què passa al *registre i a la pantalla.
- Premeu el botó de visió general (el botó quadrat a la dreta d'Inici) i tanqueu l'aplicació (toqueu la X).
- Torna a la pantalla d'inici i reinicia l'aplicació.
CONSELL: si esteu executant la vostra aplicació en un emulador, podeu simular la rotació amb Control+F11 o Control+Funció+F11.
Codi de solució de la tasca 1
Els fragments de codi següents mostren el codi de solució per a la primera tasca.
Activitat principal
Els fragments de codi següents mostren el codi afegit a MainActivity, però no tota la classe.
El mètode onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Log the start of the onCreate() method.
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
}
Altres mètodes de cicle de vida:
@Override
protected void onStart() {
super.onStart();
Log.d(LOG_TAG, "onStart");
}
@Override
protected void onPause() {
super.onPause();
Log.d(LOG_TAG, "onPause");
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(LOG_TAG, "onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.d(LOG_TAG, "onResume");
}
@Override
protected void onStop() {
super.onStop();
Log.d(LOG_TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
Segona activitat
Els fragments de codi següents mostren el codi afegit a SecondActivity, però no tota la classe.
A la part superior de la classe SecondActivity:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
El mètode returnReply():
public void returnReply(View view) {
String reply = mReply.getText().toString();
Intent replyIntent = new Intent();
replyIntent.putExtra(EXTRA_REPLY, reply);
setResult(RESULT_OK, replyIntent);
Log.d(LOG_TAG, "End SecondActivity");
finish();
}
Altres mètodes de cicle de vida:
El mateix que per a MainActivity, a dalt.
4. 4. Tasca 2: desar i restaurar l'estat de la instància d'activitat
Depenent dels recursos del sistema i del comportament dels usuaris, cada activitat de la vostra aplicació es pot destruir i reconstruir amb molta més freqüència del que podríeu pensar.
És possible que hàgiu notat aquest comportament a l'última secció quan vau girar el dispositiu o l'emulador. Girar el dispositiu és un exemple de canvi de configuració del dispositiu. Tot i que la rotació és la més habitual, tots els canvis de configuració fan que l'activitat actual es destrueixi i es torni a crear com si fos nova. Si no tens en compte aquest comportament al teu codi, quan es produeix un canvi de configuració, el disseny de l'activitat pot tornar a l'aspecte predeterminat i als valors inicials, i els usuaris poden perdre el seu lloc, les seves dades o l'estat del seu progrés a la teva aplicació.
L'estat de cada activitat s'emmagatzema com un conjunt de parells clau/valor en un objecte Bundle anomenat estat d'instància de l'activitat. El sistema desa la informació d'estat predeterminada al paquet d'estat de la instància just abans que s'atura l'activitat i passa aquest paquet a la nova instància d'activitat per restaurar-lo.
Per evitar que es perdin dades en una activitat quan es destrueix i es recrea de manera inesperada, cal que implementeu el mètode onSaveInstanceState(). El sistema crida aquest mètode a la vostra activitat (entre onPause() i onStop()) quan hi ha la possibilitat que l'activitat es destrueixi i es torni a crear.
Les dades que deseu a l'estat de la instància són específiques només d'aquesta instància d'aquesta Activitat específica durant la sessió de l'aplicació actual. Quan atureu i reinicieu una sessió d'aplicació nova, l'estat de la instància d'activitat es perd i l'activitat torna al seu aspecte predeterminat. Si necessiteu desar dades d'usuari entre sessions d'aplicacions, utilitzeu preferències compartides o una base de dades. Aprèn sobre tots dos en una pràctica posterior.
2.1 Deseu l'estat de la instància d'activitat amb onSaveInstanceState()
És possible que hàgiu notat que girar el dispositiu no afecta en absolut l'estat de la segona activitat. Això es deu al fet que el segon disseny i estat de l'activitat es generen a partir del disseny i la intenció que l'ha activat. Fins i tot si es recrea l'activitat, la intenció encara hi és i les dades d'aquesta intenció encara es fan servir cada vegada que es crida al mètode onCreate() de la segona activitat.
A més, és possible que observeu que a cada activitat, qualsevol text que heu escrit als elements EditText del missatge o de la resposta es conserva fins i tot quan es gira el dispositiu. Això es deu al fet que la informació d'estat d'alguns dels elements de Visualització del vostre disseny es desa automàticament a través dels canvis de configuració, i el valor actual d'un EditText és un d'aquests casos.
Per tant, l'únic estat d'activitat que us interessa són els elements TextView per a la capçalera de resposta i el text de resposta a l'activitat principal. Tots dos elements de TextView són invisibles per defecte; només apareixen quan envieu un missatge a l'activitat principal des de la segona activitat.
En aquesta tasca, afegiu codi per preservar l'estat d'instància d'aquests dos elements TextView mitjançant onSaveInstanceState().
- Obriu MainActivity.
- Afegiu aquesta implementació d'esquelet d'onSaveInstanceState() a l'activitat o utilitzeu Codi > Mètodes de substitució per inserir una substitució d'esquelet.
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
- Comproveu si la capçalera és visible actualment i, si és així, poseu aquest estat de visibilitat a l'estat Bundle amb el mètode putBoolean() i la clau "reply_visible".
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
}
Recordeu que la capçalera i el text de la resposta es marquen com a invisibles fins que hi hagi una resposta de la segona activitat. Si la capçalera és visible, hi ha dades de resposta que s'han de desar. Tingueu en compte que només ens interessa aquest estat de visibilitat: no cal desar el text real de la capçalera, perquè aquest text no canvia mai.
- Dins d'aquesta mateixa comprovació, afegiu el text de resposta al paquet.
outState.putString("reply_text",mReplyTextView.getText().toString());
Si la capçalera és visible, podeu suposar que el missatge de resposta també és visible. No cal que proveu ni deseu l'estat de visibilitat actual del missatge de resposta. Només el text real del missatge entra al paquet d'estat amb la clau "reply_text".
Deseu l'estat només d'aquells elements de visualització que poden canviar després de crear l'activitat. Els altres elements de visualització de la vostra aplicació (el text Edit, el botó) es poden tornar a crear des del disseny predeterminat en qualsevol moment.
Tingueu en compte que el sistema desarà l'estat d'alguns elements de la vista, com ara el contingut de l'EditText.
2.2 Restaura l'estat de la instància d'activitat a onCreate()
Un cop hàgiu desat l'estat de la instància de l'activitat, també haureu de restaurar-lo quan es torni a crear l'activitat. Podeu fer-ho a onCreate() o implementant la devolució de trucada onRestoreInstanceState(), que es crida després de onStart() després de crear l'activitat.
La majoria de les vegades, el millor lloc per restaurar l'estat de l'activitat és onCreate(), per garantir que la interfície d'usuari, inclòs l'estat, estigui disponible el més aviat possible. De vegades és convenient fer-ho a onRestoreInstanceState() després d'haver fet tota la inicialització, o permetre que les subclasses decideixin si utilitzen la vostra implementació predeterminada.
- Al mètode onCreate(), després d'inicialitzar les variables View amb findViewById(), afegiu una prova per assegurar-vos que savedInstanceState no sigui nul.
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the state.
if (savedInstanceState != null) {
}
Quan es crea la vostra activitat, el sistema passa el paquet d'estat a onCreate() com a únic argument. La primera vegada que es crida a onCreate() i s'inicia l'aplicació, el paquet és nul; no hi ha cap estat la primera vegada que s'inicia l'aplicació. Les trucades posteriors a onCreate() tenen un paquet emplenat amb les dades que heu emmagatzemat a onSaveInstanceState().
- Dins d'aquesta comprovació, traieu la visibilitat actual (vertadera o falsa) del paquet amb la clau "reply_visible".
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
}
- Afegiu una prova a sota d'aquesta línia anterior per a la variable isVisible.
if (isVisible) {
}
Si hi ha una clau reply_visible al paquet d'estats (i, per tant, isVisible és cert), haureu de restaurar l'estat.
- Dins de la prova isVisible, feu visible la capçalera.
mReplyHeadTextView.setVisibility(View.VISIBLE);
- Obteniu el missatge de resposta de text del paquet amb la clau "reply_text" i configureu la resposta TextView per mostrar aquesta cadena.
mReplyTextView.setText(savedInstanceState.getString("reply_text"));
- Feu que la resposta TextView també sigui visible:
mReplyTextView.setVisibility(View.VISIBLE);
- Executeu l'aplicació. Proveu de girar el dispositiu o l'emulador per assegurar-vos que el missatge de resposta (si n'hi ha) es mantingui a la pantalla després de recrear l'activitat.
Codi de solució de la tasca 2
Els fragments de codi següents mostren el codi de solució per a aquesta tasca.
Activitat principal
Els fragments de codi següents mostren el codi afegit a MainActivity, però no tota la classe.
El mètode onSaveInstanceState():
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// If the heading is visible, message needs to be saved.
// Otherwise we're still using default layout.
if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
outState.putBoolean("reply_visible", true);
outState.putString("reply_text",
mReplyTextView.getText().toString());
}
}
El mètode onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);
// Restore the saved state.
// See onSaveInstanceState() for what gets saved.
if (savedInstanceState != null) {
boolean isVisible =
savedInstanceState.getBoolean("reply_visible");
// Show both the header and the message views. If isVisible is
// false or missing from the bundle, use the default layout.
if (isVisible) {
mReplyHeadTextView.setVisibility(View.VISIBLE);
mReplyTextView.setText(savedInstanceState
.getString("reply_text"));
mReplyTextView.setVisibility(View.VISIBLE);
}
}
}
El projecte complet:
Projecte Android Studio: TwoActivitiesLifecycle
5. Codificació
Repte: creeu una aplicació senzilla de llista de compres amb una activitat principal per a la llista que l'usuari està creant i una segona activitat per a una llista d'articles de compres habituals.
- L'activitat principal hauria de contenir la llista per crear, que hauria d'estar formada per deu elements TextView buits.
- Un botó Afegeix un article a l'activitat principal inicia una segona activitat que conté una llista d'articles de compra habituals (Formatge, Arròs, Pomes, etc.). Utilitzeu els elements del botó per mostrar els elements.
- L'elecció d'un element retorna l'usuari a l'activitat principal i actualitza un TextView buit per incloure l'element escollit.
Utilitzeu una Intenció per passar informació d'una activitat a una altra. Assegureu-vos que l'estat actual de la llista de la compra es desa quan l'usuari giri el dispositiu.
6. Resum
- El cicle de vida de l'activitat és un conjunt d'estats pels quals migra una activitat, començant quan es crea per primera vegada i acaba quan el sistema Android recupera els recursos per a aquesta activitat.
- A mesura que l'usuari navega d'una activitat a una altra i dins i fora de la vostra aplicació, cada activitat es mou entre estats del cicle de vida de l'activitat.
- Cada estat del cicle de vida de l'activitat té un mètode de devolució de trucada corresponent que podeu substituir a la vostra classe d'activitat.
- Els mètodes del cicle de vida són onCreate(), onStart(), onPause(), onRestart(), onResume(), onStop(), onDestroy().
- La substitució d'un mètode de devolució de trucada del cicle de vida us permet afegir un comportament que es produeix quan la vostra activitat passa a aquest estat.
- Pots afegir mètodes d'anul·lació d'esquelet a les teves classes a Android Studio amb Codi > Anul·lació.
- Els canvis de configuració del dispositiu, com ara la rotació, fan que l'activitat es destrueixi i es torni a crear com si fos nova.
- Una part de l'estat d'activitat es conserva en un canvi de configuració, inclosos els valors actuals dels elements EditText. Per a la resta de dades, les heu de desar explícitament.
- Desa l'estat de la instància de l'activitat al mètode onSaveInstanceState().
- Les dades d'estat de la instància s'emmagatzemen com a parells clau/valor simples en un paquet. Utilitzeu els mètodes del paquet per introduir i recuperar dades del paquet.
- Restaura l'estat de la instància a onCreate(), que és la manera preferida, o onRestoreInstanceState(). Enrere