Maison  >  Article  >  Java  >  Bases d'Android Cycle de vie des activités

Bases d'Android Cycle de vie des activités

高洛峰
高洛峰original
2017-01-07 15:34:551282parcourir

Il en va de même pour l'apprentissage des technologies. Pour les documents techniques ou les livres techniques classiques, il est fondamentalement impossible de les comprendre complètement après les avoir lus une fois, il faut donc revenir en arrière et les lire attentivement plusieurs fois pour comprendre les pensées de l'auteur. Essence.

Récemment, j'ai révisé le cycle de vie de l'activité. J'ai lu des livres et des documents officiels pertinents et j'ai beaucoup gagné. Ma compréhension antérieure s'est grandement améliorée. J'aimerais la partager avec vous une fois.

Les amis qui connaissent JavaEE connaissent tous la technologie des servlets. Si nous voulons implémenter notre propre servlet, nous devons hériter de la classe de base correspondante et réécrire ses méthodes. Ces méthodes seront appelées par le conteneur de servlet. au moment opportun. En fait, le mécanisme d'exécution d'Activity dans Android est quelque peu similaire au servlet. Le système Android est équivalent à un conteneur de servlet, et Activity est équivalent à un servlet. Notre activité est dans ce conteneur, et tous les processus tels que la création d'instance, l'initialisation, et la destruction des instances sont effectuées par le conteneur Appelé, c'est ce qu'on appelle le mécanisme "Ne m'appelle pas, je t'appellerai".

Jetons un coup d'œil à cet organigramme classique du cycle de vie :

Bases dAndroid Cycle de vie des activités

Je crois que de nombreux amis ont déjà vu cet organigramme, et c'est essentiellement maintenant que nous comprenons plusieurs processus dans le cycle de vie de l'activité, parlons de ces processus.

1. Démarrez l'activité : le système appellera d'abord la méthode onCreate, puis appellera la méthode onStart, et enfin appellera onResume, et l'activité entrera dans l'état d'exécution.

2. L'activité en cours est écrasée par d'autres activités ou l'écran est verrouillé : le système appellera la méthode onPause pour suspendre l'exécution de l'activité en cours.

3. L'activité actuelle revient au premier plan ou déverrouille l'écran de l'état couvert : le système appellera la méthode onResume et entrera à nouveau dans l'état d'exécution.

4. L'activité actuelle passe à la nouvelle interface d'activité ou appuie sur le bouton Accueil pour revenir à l'écran d'accueil et revient en arrière-plan : le système appellera d'abord la méthode onPause, puis appellera la méthode onStop pour entrer dans un état stagnant.

5. L'utilisateur revient à cette activité : le système appellera d'abord la méthode onRestart, puis la méthode onStart, et enfin la méthode onResume pour entrer à nouveau dans l'état d'exécution.

6. L'activité en cours est écrasée ou invisible en arrière-plan, c'est-à-dire qu'aux étapes 2 et 4, le système n'a pas suffisamment de mémoire et tue l'activité en cours. Ensuite, l'utilisateur revient à l'activité en cours : appelez le. Méthode onCreate et méthode onStart à nouveau, méthode onResume, entrez dans l'état d'exécution.

7. L'utilisateur quitte l'activité en cours : le système appelle d'abord la méthode onPause, puis appelle la méthode onStop, et enfin appelle la méthode onDestory pour mettre fin à l'activité en cours.

Mais les connaître ne suffit pas. Nous devons l'essayer nous-mêmes pour le comprendre et le comprendre en profondeur.

Ci-dessous, nous utiliserons des exemples pour démontrer les détails de plusieurs processus du cycle de vie.

Nous créons un nouveau projet appelé lifecycle et créons une activité appelée LifeCycleActivity, comme suit :

package com.scott.lifecycle;
 
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
 
public class LifeCycleActivity extends Activity {
     
    private static final String TAG = "LifeCycleActivity";
    private Context context = this;
    private int param = 1;
     
    //Activity创建时被调用
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i(TAG, "onCreate called.");
     
    setContentView(R.layout.lifecycle);
     
    Button btn = (Button) findViewById(R.id.btn);
    btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(context, TargetActivity.class);
                startActivity(intent);
            }
        });
  }
   
  //Activity创建或者从后台重新回到前台时被调用
  @Override
  protected void onStart() {
    super.onStart();
    Log.i(TAG, "onStart called.");
  }
   
  //Activity从后台重新回到前台时被调用
  @Override
  protected void onRestart() {
    super.onRestart();
    Log.i(TAG, "onRestart called.");
  }
   
  //Activity创建或者从被覆盖、后台重新回到前台时被调用
  @Override
  protected void onResume() {
    super.onResume();
    Log.i(TAG, "onResume called.");
  }
   
  //Activity窗口获得或失去焦点时被调用,在onResume之后或onPause之后
  /*@Override
  public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    Log.i(TAG, "onWindowFocusChanged called.");
  }*/
   
  //Activity被覆盖到下面或者锁屏时被调用
  @Override
  protected void onPause() {
    super.onPause();
    Log.i(TAG, "onPause called.");
    //有可能在执行完onPause或onStop后,系统资源紧张将Activity杀死,所以有必要在此保存持久数据
  }
   
  //退出当前Activity或者跳转到新Activity时被调用
  @Override
  protected void onStop() {
    super.onStop();
    Log.i(TAG, "onStop called.");   
  }
   
  //退出当前Activity时被调用,调用之后Activity就结束了
  @Override
  protected void onDestroy() {
    super.onDestroy();
    Log.i(TAG, "onDestory called.");
  }
   
  /**
   * Activity被系统杀死时被调用.
   * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死.
   * 另外,当跳转到其他Activity或者按Home键回到主屏时该方法也会被调用,系统是为了保存当前View组件的状态.
   * 在onPause之前被调用.
   */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("param", param);
        Log.i(TAG, "onSaveInstanceState called. put param: " + param);
        super.onSaveInstanceState(outState);
    }
     
    /**
     * Activity被系统杀死后再重建时被调用.
     * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity.
     * 这两种情况下onRestoreInstanceState都会被调用,在onStart之后.
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        param = savedInstanceState.getInt("param");
        Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
        super.onRestoreInstanceState(savedInstanceState);
    }
}

Tout le monde a remarqué qu'en plus de plusieurs méthodes courantes, nous avons également ajouté onWindowFocusChanged, onSaveInstanceState, onRestoreInstanceState méthodes :

1. méthode onWindowFocusChanged : appelée lorsque la fenêtre d'activité gagne ou perd le focus, par exemple lorsqu'elle est présentée pour la première fois à l'utilisateur lors de sa création ; passe à une autre activité ou appuyez sur le bouton Accueil pour revenir à l'écran d'accueil et revenir en arrière-plan, l'utilisateur quitte l'activité en cours ; OnWindowFocusChanged sera appelé dans les situations ci-dessus, et lorsque l'activité est créée, elle est appelée après onResume. Lorsque l'activité est écrasée ou retirée en arrière-plan ou que l'activité actuelle se termine, elle est appelée après onPause, comme le montre la figure :

Bases dAndroid Cycle de vie des activités

Cette méthode est toujours très utile dans certaines situations. Par exemple, lorsque vous souhaitez obtenir la taille d'un composant de vue spécifique au démarrage du programme, vous ne pourrez peut-être pas le faire. pour l'obtenir dans onCreate car l'objet window L'objet Window n'a pas encore été créé, nous devons donc l'obtenir dans onWindowFocusChanged à ce moment-là ; si vous avez lu l'article que j'ai écrit sur Frame Animation pour l'animation Android, vous saurez que la raison ; pourquoi la tentative de chargement de l'animation d'image dans onCreate a échoué parce que l'objet window n'a pas été initialisé, donc à la fin j'ai mis le code pour charger l'animation dans onWindowFocusChanged et le problème a été résolu. Cependant, vous vous demandez peut-être pourquoi je l'ai commenté dans le code, car chaque opération de l'activité en cours a son journal d'exécution. J'avais peur que cela n'affecte la clarté de l'ensemble du processus, alors je l'ai commenté. comprendre les occasions où il est appliqué et l’ordre d’exécution.

2.onSaveInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;(2)在用户改变屏幕方向时,此方法会被调用;(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState的调用顺序是在onPause之前。

3.onRestoreInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。onRestoreInstanceState的调用顺序是在onStart之后。

以上着重介绍了三个相对陌生方法之后,下面我们就来操作一下这个Activity,看看它的生命周期到底是个什么样的过程:

1.启动Activity:

在系统调用了onCreate和onStart之后,调用了onResume,自此,Activity进入了运行状态。

2.跳转到其他Activity,或按下Home键回到主屏:

我们看到,此时onSaveInstanceState方法在onPause之前被调用了,并且注意,退居后台时,onPause后onStop相继被调用。

3.从后台回到前台:

当从后台会到前台时,系统先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,Activity又进入了运行状态。

4.修改TargetActivity在AndroidManifest.xml中的配置,将android:theme属性设置为@android:style/Theme.Dialog,然后再点击LifeCycleActivity中的按钮,跳转行为就变为了TargetActivity覆盖到LifeCycleActivity之上了,此时调用的方法为:

注意还有一种情况就是,我们点击按钮,只是按下锁屏键,执行的效果也是如上。

我们注意到,此时LifeCycleActivity的OnPause方法被调用,并没有调用onStop方法,因为此时的LifeCycleActivity没有退居后台,只是被覆盖或被锁屏;onSaveInstanceState会在onPause之前被调用。

5.按回退键使LifeCycleActivity从被覆盖回到前面,或者按解锁键解锁屏幕:

此时只有onResume方法被调用,直接再次进入运行状态。

6.退出:

最后onDestory方法被调用,标志着LifeCycleActivity的终结。

大家似乎注意到,在所有的过程中,并没有onRestoreInstanceState的出现,这个并不奇怪,因为之前我们就说过,onRestoreInstanceState只有在杀死不在前台的Activity之后用户回到此Activity,或者用户改变屏幕方向的这两个重建过程中被调用。我们要演示第一种情况比较困难,我们可以结合第二种情况演示一下具体过程。顺便也向大家讲解一下屏幕方向改变的应对策略。

首先介绍一下关于Activity屏幕方向的相关知识。

我们可以为一个Activity指定一个特定的方向,指定之后即使转动屏幕方向,显示方向也不会跟着改变:

1.指定为竖屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="portrait",或者在onCreate方法中指定:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//竖屏

2.指定为横屏:在AndroidManifest.xml中对指定的Activity设置android:screenOrientation="landscape",或者在onCreate方法中指定:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//横屏

为应用中的Activity设置特定的方向是经常用到的办法,可以为我们省去不少不必要的麻烦。不过,我们今天讲的是屏幕方向改变时的生命周期,所以我们并不采用固定屏幕方向这种办法。


下面我们就结合实例讲解一下屏幕转换的生命周期,我们新建一个Activity命名为OrientationActivity,如下:

package com.scott.lifecycle;
 
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
 
public class OrientationActivity extends Activity {
     
    private static final String TAG = "OrientationActivity";
    private int param = 1;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.orientation_portrait);
        Log.i(TAG, "onCreate called.");
    }
     
    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "onStart called.");
    }
     
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "onRestart called.");
    }
     
    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume called.");
    }
     
    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause called.");
    }
     
    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop called.");
    }
     
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestory called.");
    }
 
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt("param", param);
        Log.i(TAG, "onSaveInstanceState called. put param: " + param);
        super.onSaveInstanceState(outState);
    }
     
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        param = savedInstanceState.getInt("param");
        Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
        super.onRestoreInstanceState(savedInstanceState);
    }
     
    //当指定了android:configChanges="orientation"后,方向改变时onConfigurationChanged被调用
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.i(TAG, "onConfigurationChanged called.");
        switch (newConfig.orientation) {
        case Configuration.ORIENTATION_PORTRAIT:
            setContentView(R.layout.orientation_portrait);
            break;
        case Configuration.ORIENTATION_LANDSCAPE:
            setContentView(R.layout.orientation_landscape);
            break;
        }
    }
}

首先我们需要进入“Settings->Display”中,将“Auto-rotate Screen”一项选中,表明可以自动根据方向旋转屏幕,然后我们就可以测试流程了,当我们旋转屏幕时,我们发现系统会先将当前Activity销毁,然后重建一个新的:

Bases dAndroid Cycle de vie des activités

Le système appelle d'abord la méthode onSaveInstanceState. Nous enregistrons un paramètre temporaire dans l'objet Bundle, puis nous récupérons avec succès ce paramètre une fois l'activité reconstruite.

Afin d'éviter ce processus de destruction et de reconstruction, nous devons configurer android:configChanges="orientation" pour l' correspondant à OrientationActivity dans AndroidMainfest.xml, puis nous le testons à nouveau. faire quatre La rotation est imprimée comme suit :

Bases dAndroid Cycle de vie des activités

Vous pouvez voir qu'à chaque fois que la direction est tournée, seule la méthode onConfigurationChanged est appelée, et il n'y a pas de destruction ni de reconstruction processus.

Voici quelques points à noter :

1. Si est configuré avec l'attribut android:screenOrientation, cela invalidera android:configChanges="orientation".

2. Il y a une grande différence entre le simulateur et la machine réelle : si l'attribut android:configChanges n'est pas configuré dans le simulateur ou si la valeur de configuration est l'orientation, passez à l'écran horizontal et exécutez une destruction - > reconstruisez, passez à l'écran vertical et exécutez deux fois. Les vraies machines sont toutes une fois. Si vous configurez android:configChanges="orientation|keyboardHidden" (s'il s'agit d'Android 4.0, il s'agit de "orientation|keyboardHidden|screenSize") dans le simulateur, onConfigurationChanged sera exécuté une fois lors du passage à l'écran vertical et deux fois lors du passage à l'écran horizontal. écran. Les vraies machines sont toutes une fois.

Le cycle de vie de l'activité est indissociable de la robustesse du programme. J'espère que les amis pourront le comprendre attentivement et l'appliquer habilement.


Pour plus d'articles liés au cycle de vie des activités des bases d'Android, veuillez faire attention au site Web PHP chinois !


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn