Activity的生命周期

匿名 (未验证) 提交于 2019-12-03 00:27:02

Activity作为Android的四大组件之首,生命周期当然是重中之重了。
虽然都是老生常谈的面试题了。。。但是被面试官问到了,还是不会的话,

Activity―其实我更愿意喊它一声“界面”呗。我们在手机上看到的一个窗口,就是它啊。
它的生命周期也分为两种情况:
第一:正常情况下的生命周期
第二:非正常情况下的生命周期:比如屏幕翻转或者内存不足,被kill掉了。

一、 Activity有哪些生命周期方法

先来过滤一下,一共有哪些生命周期的方法吧!

  • onCreate:表示窗口正在被创建,比如加载layout布局文件啊(setContentView)。 所以我们可以在这个方法中,做一些初始化的操作。

  • onStart:表示Activity正在被启动,即将开始,此时的窗口已经可见了,但是还没有出现在前台,所以无法和用户进行交互。也就是说此时的窗口正处在 不可见―>可见 的过程中。

  • onRestart:表示窗口正在重新启动。在什么场景下会调用这个呢?比如:从A页面进入B页面,然后点击BACK键(或者自己的返回上一页的按钮)回到A页面,那么就会调用A页面的onRestart方法了。。(当前也牵扯到A和B页面的其他生命周期方法的调用,这个我们后面再详细说明)
    再比如:点击HOME键回到桌面,然后通过点击任务栏或者点击应用图标再次进入A页面,都可以触发调用这个方法

  • onResume:表示此时的窗口已经可见了,显示在前台并且进行活动了,我们也可以与窗口进行交互了。

  • onPause:表示窗口正在停止,这是我们可以做一些存储数据、或者停止动画等一些不太耗时的操作,因为会影响到下一个Activity的显示。onPause执行完成之后,新的Activity的onResume才会执行。

  • onStop:表示窗口即将停止,此时,可以做一些稍微重量级的回收工作,但是也不能太耗时哈。

  • onDestroy:表示窗口即将被销毁。这是Activity生命周期中的最后一步了。这里,我们可以做一些回收工作和最终的资源释放工作。

下面,我们暴露一张图,来详细的描述一下窗口的生命周期的切换过程:
(此图是任玉刚的《Android开发艺术探索》里面的,懒,不想自己画了。)

二、正常情况下,Activity的生命周期调用过程

然后我们来梳理一下几种情况下,生命周期的方法调用顺序是怎么样的。

  1. 启动一个特定的Activity时,第一次启动,生命周期回调如下:

  2. 当用户打开新的Activity或者切换到桌面的时候,回调如下:

    但是有一种特殊的情况,如果新的Activity采用了透明的主题,那么当前Activity不会回调onStop

  3. 当用户再次回到原Activity时,回调如下:

  4. 当用户点击Back键回退时,回调:

  5. 在生命周期中,onCreate和onDestroy是对应的,创建和销毁,并且在生命周期过程中,只被调用一次。从Activity是否可见来说,onStart和onStop是配对的,这两个方法有可能会被多次调用。从Activity是否在前台来说,onResume和onPause是配对的,也有可能会被多次调用。

其中有两个问题:
第一:onStart和onResume,onPause和onStop差不对,但是又有什么本质的不同呢?
第二:当从A 窗口打开B窗口时,B窗口的onResume和A的onPause方法哪个先执行呢?

首先第一个问题:
从上面的描述中就知道了,虽然差不多,但是角度还是不通的。onStart和onStop从Activity是否可见来说的,onResume和onPause从Activity是否在前台来说的。其他的就没有什么区别了。

第二问题:
自己实践一下就知道了,先是A的onPause方法调用结束之后,才会执行B窗口的onResume方法。当然还是从源码了解的更彻底。。。请参考任玉刚的《Android开发艺术探索》或者自己去 AndroidXRef 看吧。

三、非正常情况下,Activity的生命周期调用过程

非正常情况下,比如屏幕的旋转,或者内存不够用的情况下,由系统的回收操作造成的非前台的Activity被意外杀死的情况。
盗一图,来源:任玉刚的《Android开发艺术探索》

屏幕旋转下的生命周期

我们用实例来说明
在LunchAActivity中,我们在Logcat中打印所有的生命周期方法

import android.content.Intent; import android.os.Bundle; import android.os.PersistableBundle; import android.support.v7.app.AppCompatActivity; import android.widget.Button; import android.widget.TextView;  import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import demo.learn.com.learndemo.R; import demo.learn.com.learndemo.utls.LogUtils;  public class LunchAActivity extends AppCompatActivity {     @BindView(R.id.btn_jump)     Button btnJump;     @BindView(R.id.tv_save)     TextView tvSave;     private String saveValues = "";      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_lunch_a);         ButterKnife.bind(this);         LogUtils.logE("LunchAActivity", "onCreate");     }      @Override     protected void onSaveInstanceState(Bundle outState) {         super.onSaveInstanceState(outState);         outState.putString("savevalue", "意外保存的结果");         LogUtils.logE("LunchAActivity", "onSaveInstanceState");     }      @Override     public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {         super.onSaveInstanceState(outState, outPersistentState);     }      @Override     protected void onRestoreInstanceState(Bundle savedInstanceState) {         super.onRestoreInstanceState(savedInstanceState);         saveValues = savedInstanceState.getString("savevalue");         LogUtils.logE("LunchAActivity", "onRestoreInstanceState");     }      @Override     public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {         super.onRestoreInstanceState(savedInstanceState, persistentState);     }      @Override     protected void onRestart() {         super.onRestart();         LogUtils.logE("LunchAActivity", "onRestart");     }      @Override     protected void onStart() {         super.onStart();         LogUtils.logE("LunchAActivity", "onStart");     }      @Override     protected void onResume() {         super.onResume();         LogUtils.logE("LunchAActivity", "onResume");         tvSave.setText(saveValues);     }      @Override     protected void onPause() {         super.onPause();         LogUtils.logE("LunchAActivity", "onPause");     }      @Override     protected void onDestroy() {         super.onDestroy();         LogUtils.logE("LunchAActivity", "onDestroy");     }      @OnClick(R.id.btn_jump)     public void onViewClicked() {         Intent intent = new Intent(this, LunchBActivity.class);         startActivity(intent);     } } 

正常打开页面的生命周期回调如下:

然后,旋转屏幕之后,打印出来的生命周期如下:


注意这里不走onRestart方法,这里是销毁窗口之后并重建,慢慢领会一下,实在不行,自己动手操作实践一遍就哦了。

资源内存不足导致低优先级的Activity被杀死的情况下

这种情况不好模拟,但是保存数据的过程和恢复数据的过程是一模一样的。
而且回收过程中,牵扯到Activity的优先级,所以我们来讨论一下Activity的优先级:

  • ǰ̨Activity
    正在和用户进行交互的窗口,优先级最高

  • 可见但是非前台的Activity
    比如Activity中弹出一个对话框,导致Activity可见但是不可交互

  • 后台Activity
    已经被暂停的Activity,比如执行了onStop方法的窗口,优先级最低

    当系统内存不足时,就会按照优先级去kill掉目标Activity所在的进程,并执行onSaveInstanceState和onRestoreInstanceState来保存和恢复数据。
    而且一个进程中如果没有四大组件在运行,那么这个进程很容易被杀死。
    所以一些后台进程不适合脱离四大组件独立运行。最好将一些重要的后台操作放在Service中,这样保证一定的优先级,就不会轻易被系统杀死。

如果我们想让屏幕在旋转时不销毁并重建页面,可以在AndroidManifest.xml中给Activity配置一下configChanges,如下图

两个参数缺一不可
并且在Activity中重新onConfigurationChanged方法

这样在旋转屏幕时,就不会销毁并重建Activity了。只会调用这个onConfigurationChanged回调方法。
当然我们也可以禁止屏幕旋转,通过 android:screenOrientation=”portrait”只让屏幕保持竖屏。

待定……
下一章节,复习一下Activity的四中启动模式。。。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!