好好找job

Activity的生命周期

2018-04-02  本文已影响14人  S_ZY

清明时节雨纷纷。路上行人欲断魂

1.正常情况下的生命周期

1.onCreate:onDestory配对,表示Activity被创建,这是生命周期的第一个方法。在这方法中可以做一个初始化的工作(比如加载布局资源,初始化activity所需要的数据等),耗时的工作在异步线程上完成。

2.onRestart:表示Activity正在重新启动一般情况下,在当前Actiivity从不可见重新变为可见状态时onRestart就会被调用。这种请求一般都是用户行为所导致的,比如用户按下Home键切换到桌面或者打开了一个新的Activity(这时当前的Activity会暂停,也就是onPause和onStop被执行),接着用户回到了这个Activity就会出现这种情况。

3.onStart:onStop配对,表示Activity正在被启动,并且即将开始。但是这个时候要注意他与onResume的区别,两者都标识Avtivity可见,但是onStartActivity还在加载其他内容,正在像我们展示,用户还无法看到,即无法交互。

4.onResume:onPause配对,表示Activity已经创建完成,并可以开始活动了,这个时候用户可以看到界面,并且即将与用户交互 (完成该周期之后便可以响应用户的交互事件了)。

5.onPause:onResume配对,表示Activity正在暂停,正常情况下,onStop接着就会被调用,在特殊情况下,如果这个时候用户快速的再回到当前Activity,那么onResume会被调用(极端情况),一般来说,在onPause这个生命周期状态下可以做一些数据存储,停止动画的工作,但是不能太耗时,,如果是由于启动新的Activity而唤醒的该状态,那会影响到新Activity的显示,原因是onPause必须执行完,新的ActivityonResume才会执行。

6.onStop:onStart配对,表示Activity即将停止,可以做一些稍微重量级的回收工作,同样也不能太耗时(可以比onPause稍微好一点)。

7.onDestroy:与onCreate配对,表示Activity即将被销毁,这是Activity生命周期的最后一个回调,我们可以做一些回收工作和最终的资源释放(如ServiceBroadReceiverMap等)。

正常情况下,Activity的常用生命周期就是上面的7个,下图更加详细的描述的各种生命周期的切换过程:

9KP_EEF`(~_VRX8R2BH07AL.png

这里要说的是,从上图我们可以看到一个现象:
onStartonStoponResumeonPause是配对的。两种Activity回到前台的方式,从onPause状态回到前台会走到onResume状态,从onStop状态回到前台会到onStart状态,这是从是否可见和是否在前台来说的。从是否可见来说,onStartonStop是配对的;从是否在前台来说,onResumeonPause是配对的。

我们来看看正常情况下生命周期的系统日志:

03-23 00:15:52.970 32278-32278/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:15:52.971 32278-32278/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:15:52.971 32278-32278/com.example.david.lifecircle E/TAG: onResume() is invoked!
03-23 00:15:55.858 32278-32278/com.example.david.lifecircle E/TAG: onPause() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onRestart() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:16:02.573 32278-32278/com.example.david.lifecircle E/TAG: onResume() is invoked!

2.异常情况下的生命周期

一般正常情况的声明周期就像上面所说的一样,但是因为Android本身内存或者其他的一些情况会使得Activity不按照正常的生命周期。比如当资源配置发生改变、系统内存不足时,Activity就会被杀死。下面分析这两种常见的情况。
情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建
理解这个问题,我们首先要对系统的资源加载机制有一定了解,不过这里我不分析系统资源加载机制了(因为我也不怎么懂)。简单说明一下,就像是我们把一张图片放在drawable目录之后,就可以通过Resources去获取这张图片。同时为了兼容不同的设备,我们还可能需要在其他的一些目录放置不同的图片,比如 drawable-mdpidrawable-hdpi等。这样,当应用程序启动时,系统就会根据当前设备的情况去加载合适的Resource资源,比如说横屏和竖屏的手机会拿到两张不同的图片(设定了landscapeportrait状态下的图片)。
如果说,当前Activity处于竖屏状态,如果突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并重新创建(当然我们也可以组织系统重新创建,具体就在Mainfest中申明android:Configchanges=属性即可)。

异常情况下的调用流程:
1.调用onSaveInstance保存当前Activity状态。注意,它与onPause方法没有先后之分。
2.调用onStop方法做后续处理。
3.调用onDestroy方法销毁当前活动。
4.重新onCreate该活动。
5.调用onStart方法之后,再调用onRestoreInstance方法加载保存的数据。
6.接下来就与正常的一样了,调用onResume,然后运行。

我们来看一下生命周期异常运行的系统日志:
03-23 00:19:23.480 26457-26457/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:19:23.481 26457-26457/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:19:23.481 26457-26457/com.example.david.lifecircle E/TAG: onResume() is invoked!
03-23 00:19:51.323 26457-26457/com.example.david.lifecircle E/TAG: onPause() is invoked!
03-23 00:19:51.324 26457-26457/com.example.david.lifecircle E/TAG: onSaveInstanceState() is invoked!  Save Text = Save Data
03-23 00:19:51.478 26457-26457/com.example.david.lifecircle E/TAG: onCreate() is invoked!
03-23 00:19:51.488 26457-26457/com.example.david.lifecircle E/TAG: onStart() is invoked!
03-23 00:19:51.490 26457-26457/com.example.david.lifecircle E/TAG: onRestoreInstanceState() is invoked!  Recover Text = Save Data
03-23 00:19:51.490 26457-26457/com.example.david.lifecircle E/TAG: onResume() is invoked!

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

这种情况不好模拟,但是其数据存储和恢复过程和情况1完全一致,这里简单的描述一下Activity的优先级情况。Activity的优先级从高到低可以大致分为一下三种:

(1)前台Activity——正在和用户交互的Activity,优先级最高。
(2)可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见但无法和用户直接交互。
(3)后台Activity——已经被暂停或者停止的Activity,优先级最底。

当系统内存不足的时候,系统就会按照上述优先级从低到高来杀死目标Activity。并在后续通过onSaveInstanceonRestoreInstance来存储和恢复数据。
特别提醒的是:如果一个进程中没有四大组件(ActivityServiceContentProviderBroadCastReceiver)。那么这个进程就会很快被杀死,因此一些后台工作不适合脱离四大组件而独立运行在后台中,否则很容易被杀死。一般是将后台工作放入Service中从而保证进程有一定的优先级,这样才不会被系统轻易杀死

三、生命周期的使用

1.常见的生命周期有关问题:

1.onStartonResumeonPauseonStop从描述上看来差不多,但是他们为什么会分开呢?有什么不同?
2.两个Activity AB,从A中启动B,那么BonResumeAonPause哪个会先执行呢?
3.onSaveInstanceonRestoreInstance是任何情况下都可以使用的嘛?所有的保存数据和恢复的操作都可以在这对方法中执行?
4.如上面所说,如何使得在系统配置放生改变后,Activity不被重新创建呢?

2.解析

1、 onStartonResumeonPauseonStop这两对看起来是差不多,而且很多时候都会同时调用onPauseonStop,然后回到onStartonResume。但是在一些比较特殊的情况下就不一样了。我们举两种情况,
第一种:前台弹出了一个Dialog,那么这个Dialog的作用只是提醒用户或者让用户输入一个信息等就完毕了,这是一个比较轻量级的任务;
第二种:重新启动另一个Activity界面,转到另一个模块。这时新启动的Activity就不是一个临时或者轻量级的任务了。
这两种情况,第一种一般很快就会返回当前Activity,不会太耗时;第二种可能会很久,在这段时间内系统可能需要启动其他的应用,那么就会产生内存紧张的问题。所以,我认为是要区分这两种情况,才会加入这两对方法。在第一种情况下,可以在onPause中做一些较轻微的数据存储,因为一般很快就会回到当前Activity;第二种情况下,适合在onStop中做一些较重量级的存储。除此之外,我想不到其他的使用了。

2、这个问题可以从源码中得到解答。不过源码太复杂,涉及底层太多(AMSBinderActivityStackActivityThread等)。不过可以直接调用生命周期,输出系统日志来得到解答。从下面的日志我们可以看出,的确是要等到A活动的onPause方法之后B才能执行(这里onCreate没有输出日志):

03-23 01:02:31.339 32382-32382/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
03-23 01:02:31.341 32382-32382/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
03-23 01:02:31.341 32382-32382/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
03-23 01:04:04.005 32382-32382/com.example.david.lifecircle E/MainActivity: onPause() is invoked!
03-23 01:04:04.047 32382-32382/com.example.david.lifecircle E/SecondActivity: onStart() is invoked!
03-23 01:04:04.047 32382-32382/com.example.david.lifecircle E/SecondActivity: onResume() is invoked!

3、 onSaveInstanceonRestoreInstance是只有Activity异常销毁的时候才会调用的,所以这里一般执行的是Activity异常销毁时需要保存和恢复的数据;onSaveInstanceonRestoreInstance方法还可以判断Activity是否被重建,但正常情况下是不会调用的。所以正常情况下,还是应该在onPauseonStop方法中保存数据。

4、上面提到,我们可以在AndroidMainfest.xml里,对< activity />增加一个android:configChanges属性,来指定在哪些配置改变的情况下Activity不需要重建。如下所示:

android:configChanges="orientation|screenSize"//界面方向以及大小的改变不需要重建

我们在AndroidMainfest.xml做如下申明:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.david.lifecircle">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:configChanges="orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity"></activity>
    </application>

</manifest>

MainActivity中的部分代码:

 @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.e("MainActivity","onConfigurationChanged() is invoked!"+newConfig.orientation);
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e("MainActivity","onPause() is invoked!");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("MainActivity","onResume() is invoked!");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e("MainActivity","onStart() is invoked!");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e("MainActivity","onRestart() is invoked!");
    }

点击屏幕旋转,然后来看一下系统日志输出:

03-23 01:14:11.357 10361-10361/com.example.david.lifecircle E/MainActivity: onCreate() is invoked!
03-23 01:14:11.359 10361-10361/com.example.david.lifecircle E/MainActivity: onStart() is invoked!
03-23 01:14:11.359 10361-10361/com.example.david.lifecircle E/MainActivity: onResume() is invoked!
03-23 01:14:28.140 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!2
03-23 01:14:38.294 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChanged() is invoked!1
03-23 01:14:47.531 10361-10361/com.example.david.lifecircle E/MainActivity: onConfigurationChan

我们发现,屏幕旋转之后,并没有重新调用生命周期,说明活动并没有被重建。configChanges属性还有许多的值,如:mcc\mnc\local\touchscreen\keyboard等等。

最后用一个实际的例子来说明Activity的各个生命周期。假设有一个程序由2个Activity`` AB组成,A是这个程序的启动界面。当用户启动程序时,Process和默认的Task分别被创建,接着A被压入到当前的Task中,依次执行了 onCreate, onStart, onResume事件被呈现给了用户;此时用户选择A中的某个功能开启界面B,界面B被压入当前Task遮盖住了AAonPause事件执行,BonCreate, onStart, onResume事件执行,呈现了界面B给用户;用户在界面B操作完成后,使用Back键回到界面A,界面B不再可见,界面BonPause, onStop, onDestroy执行,AonResume事件被执行,呈现界面A给用户。此时突然来电,界面AonPause事件被执行,电话接听界面被呈现给用 户,用户接听完电话后,又按了Home键回到桌面,打开另一个程序“联系人”,添加了联系人信息又做了一些其他的操作,此时界面A不再可见,其 onStop事件被执行,但并没有被销毁。此后用户重新从菜单中点击了我们的程序,由于A和其所在的进程和Task并没有被销毁,AonRestartonStart事件被执行,接着AonResume事件被执行,A又被呈现给了用户。用户这次使用完后,按Back键返回到桌面,AonPause, onStop被执行,随后AonDestroy被执行,由于当前Task中已经没有任何ActivityA所在的Process的重要程度被降到很 低,很快A所在的Process被系统结束
常见的例子

情形一、一个单独的Activity的正常的生命过程是这样的:onCreate->onStart->onPause->onStop->onDestroy。例如:运行一个Activit,进行了一些简单操作(不涉及页面的跳转等),然后按返回键结束。

情形二、有两个Activity(a和b),一开始显示a,然后由a启动b,然后在由b回到a,这时候a的生命过程应该是怎么样的呢(a被b完全遮盖)?

a经历的过程为onCreate->onStart->onResume->onPause->onStop->onRestart->onStart->onResume。这个过程说明了图中,如果Activity完全被其他界面遮挡时,进入后台,并没有完全销毁,而是停留在onStop状态,当再次进入a时,onRestart->onStart->onResume,又重新恢复。

情形三、基本情形同二一样,不过此时a被b部分遮盖(比如给b添加个对话框主题 android:theme=”@android:style/Theme.Dialog”)

a经历的过程是:onCreate->onStart->onResume->onPause->onResume

所以当Activity被部分遮挡时,Activity进入onPause,并没有进入onStop,从Activity2返回后,执行了onResume

情形四、 打开程序,启动a,点击a,启动AlertDialog,按返回键从AlertDialog返回。

a经历的过程是:onCreate->onStart->onResume

当启动和退出Dialog时,Activity的状态始终未变,,因为Dialog实际上时一个View,它是属于某一个Activity的,因此如果Dialog显示在当前Activity之前时不会影响到Activity的生命周期的。但是如果是其他ActivityDialog弹出那么就会触发onPause()方法的执行。

摘自 https://blog.csdn.net/woshimalingyi/article/details/50961380

上一篇下一篇

猜你喜欢

热点阅读