Android关于Activity知识点总结(一)生命周期与状态及状态保存

以下内容为复习总结,若有幸被大神看到,望指正其不准,补充其不足。万分感谢!!!

Android关于Activity知识点总结(二)任务、返回栈与启动模式

一、概述

Activity是Android的一个应用组件,它提供一个界面与用户进行交互,用户可通过点击、滑动等事件来执行拨打电话,发送信息邮件或查看地图等操作。每个Activity都获得一个用于绘制用户界面的窗口,窗口通常是充满屏幕的,但也可以小于屏幕并浮于其他窗口上。

二、Activity的四种状态

1、Running状态:一个新的Activity启动后,它位于屏幕的最前端,也位于栈(下面会写到)的最顶端,此时的Activity处于可见并可交互状态,即用户可直接进行点击,滑动等操作。Android也会试图最大可能的保持它的活动状态,杀死其他Activity来确保当前活动的Activity有足够的资源可使用,对应生命周期为onResume()。当另外一个Activity被激活时,此状态将转被暂停,变为Paused状态,对应生命周期为onPause()。

2、Paused状态:当Activity处于此状态时,它依然与窗口管理器保持联系,系统继续维护其内部状态,它仍然可见,但失去了焦点,不可与用户进行交互。此状态对应,在其上面打开一个对话框或是打开一个背景为透明的Activity,对应生命周期为onPause()。

3、Stopped状态:当Activity不可见时,此Activity处于Stopped状态时。需要注意的是,Activity在此状态时,如果下次激活此Activity时要使用之前的数据和UI状态,则一定要进行保存,否则一旦Activity关闭或退出时,当前数据和UI状态将丢失,此时对应生命周期为onStop()。

4、Killed状态:Activity被销毁或者启动之前,处于此状态。这时Activity已被从Activity栈中移除,需要重启才可以显示和使用,对应生命周期为:onDestroy()或被系统回收。

此为四种状态转换关系图:

三、Activity的生命周期和各阶段触发的事件

Activity共有七个生命周期方法:onCreate(),onRestart(),onStart(),onReusme(),onPause(),onStop(),onDestory()。

其中:onCreate()和onDestory(),onStart()和onStop(),onReusme()和onPause()和三对是一一对应关系。

以下为各生命周期方法之间调用关系图:谷歌官方图

1、Activity launched:

此操作为点击桌面图标启动程序。

2、onCreate()方法:

此方法只在Activity第一次被创建时调用,主要负责Activity的一般性的初始化设置,包括视图的创建(setContentView()),视图数据的绑定等等。

需要注意的是:若此Activity销毁前有对其数据或state进行保存(即系统对该Activity调用过onSaveInstanceState()函数),则可以通过其Bundle参数进行state恢复。

3、onStart()方法:

Activity正在由不可见变为可见时,会执行此方法,即(此时Activity已经可见了)只是用户是不可以与之交互的。此时可以注册一个广播。

此时有个特殊情况:就是当上面覆盖一个透明主题的Activity或上边有个对话框类型时,再返回此Activity不会调用此方法,因为此时Activity已为可见,正处于此生命周期中。

4、onResume()方法:

当Activity处于屏幕最前端时,此Activity处于可见并可以与用户进行交互操作。此时的Activity也处在Activity栈顶。

生命周期运行到此方法时,Activity处于Running状态。

特殊情况:同第三点onStart()中,此Activity被对话框类型或透明主题的Activity遮挡,当这个对话框类型组件或透明主题的Activity消失时,会触发此方法,而不是触发onStart()方法。

5、Activity Running :

此时Activity正处于激活状态,正在与用户进行交互。此时持续处于Running状态。

6、onPause()方法:

当Activity失去焦点时(即不可与用户进行交互),此时Activity无论是部分遮挡还是即将被全部遮挡,会回调此方法。此时返回此Activity使其重新获得焦点,则会执行onResume()方法(即6->4过程),所以他们两个是一一对应的。

此时Activity处于Pause状态(即暂停状态),此时Activity还是可见的。

需要注意:Android中指定如果onPause()在500ms内没有执行完毕的话就会强制关闭Activity,因此不可做耗时操作。

7、onStop()方法:

当Activity不需要展示给用户时,即完全不可见,可能是由于此Activity要被注销或者新的Activity完全遮挡此Activity,就会回调此方法。当Activity由不可见到可见过程中(7->10->3),会执行onRestart()方法,然后最终执行onStart()方法,此时Activity可见。

此时Activity处于Stopped状态。如果内存,紧张系统直接销毁Activity,则Activity将处于Killed状态。

需要注意:此时Activity还在内存中,没有被回收,如果内存紧张,系统会直接销毁Activity,而不会触发onStop()方法,所以要保存状态和信息时,应该在onPause()方法中,因为有可能onPause()方法会是Activity最后的生命周期方法。

8、onDestroy()方法:

当Activity被销毁时,会回调此方法,此方法只会调用一次。和onStop()方法一样,当内存紧张时会直接销毁Activity,而不会回调此方法。

此时Activity处于Killed状态。如果内存紧张,系统直接销毁Activity,则处于Killed状态。

9、Process is Killed :

Activity处于Killed状态,此效果和执行onDestroy()方法等效,都需要从新创建Activity实例。

触发条件:当内存紧张时Activity声明周期将不会执行完,即可能直接执行7->9或6->9,而不走完整的生命周期。

10、onRestart()方法:

此方法在Activity执行onStop()方法后,Activity重新由不可见到可见的过程中(onStart()方法之前)会执行。即在刚开始创建Activity时不会执行此方法。

此时Activity处于Stopped状态向Running状态过渡。

11、Activity shut down:

此时Activity被销毁,也可能是对应1的程序关闭。

四、Activity的几种跳转方式所执行的生命周期顺序

1、对于一个Activity创建销毁过程:

当启动Activity时:onCreate()->onStart()->onResume();

当按home键时:onPause()->onStop;

再次回到原Activity时:onRestart()->onStart()->onResume();

当退出当前Activity时:onPause()->onStop()->onDestory()。

2、当在A_Activity中跳转到B_Activity时:

先启动A时执行:onCreate()->onStart()->onResume();

然后打开B时:先执行A的onPause(),然后执行B的onCreate()->onStart()->onResume();

此时有两种情况:

(a)、当B_Activity完全覆盖A_Activity,此时A完全不可见,则执行A的onStop()方法,这时如果A调用finish()方法,则A还会执行onDestory();

   此时当从B_Activity返回A_Activity时,B执行onPause(),如果A未执行onDestory()方法时,A执行onRestart()->onStart()->onResume(),如果执行了onDestory()方法,则需要重新创建A的实例。

(b)、当B_Activity为透明主题或者是对话框的样式时,此时不会执行A的onStop()方法。

         此时当从B_Activity返回A_Activity时,B执行onPause(),A执行onResume(),

3、当横竖屏切换时:

横竖屏切换会涉及到Activity的 android:configChanges属性,这些属性包括如下:

(a)、orientation:消除横竖屏的影响

(b)、keyboardHidden:消除键盘的影响

(c)、screenSize:消除屏幕大小的影响,此属性值在android3.2以后添加

所以横竖屏切换时根据 android:configChanges 不同的属性值表现的方式也不同:

当前版本下真机实测:

(a)、当不设置Activity的android:configChanges 值时,横竖屏切换时会重新调用生命周期,先销毁Activity,再重建。

切换横竖屏时,生命周期只会执行一次,而不会执行onConfigurationChanged()方法:

onPause-->onSaveInstanceState-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume;

(b)、当设置Activity的android:configChanges="orientation"android:configChanges="orientation|keyboardHidden" 值时,

竖屏切换到横屏时,会重新调用生命周期,但先执行onConfigurationChanged()方法,然后销毁Activity,再重建。

onConfigurationChanged-->onPause-->onSaveInstanceState-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume;

横屏切换到竖屏时,只会执行onConfigurationChanged()方法,而不会重新调用生命周期:

onConfigurationChanged()方法

(c)当设置Activity的android:configChanges="orientation|keyboardHidden|screenSize" 值时,横竖屏切换时不会调用生命周期,执行onConfigurationChanged()方法。

注:screenSize 是在android3.2以后才出现,在3.2之前android:configChanges="orientation|keyboardHidden"的效果和以上c中一样,未实测。

以下为测试代码:

public class SwitchScreenOrientationActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_move);
        System.out.println("SwitchScreenOrientationActivity----->onCreate");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.out.println("SwitchScreenOrientationActivity----->onDestroy");
    }

    @Override
    protected void onPause() {
        super.onPause();
        System.out.println("SwitchScreenOrientationActivity----->onPause");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        System.out.println("SwitchScreenOrientationActivity----->onRestart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("SwitchScreenOrientationActivity----->onResume");
    }

    @Override
    protected void onStart() {
        super.onStart();
        System.out.println("SwitchScreenOrientationActivity----->onStart");
    }

    @Override
    protected void onStop() {
        super.onStop();
        System.out.println("SwitchScreenOrientationActivity----->onStop");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        System.out.println("SwitchScreenOrientationActivity----->onRestoreInstanceState");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        System.out.println("SwitchScreenOrientationActivity----->onSaveInstanceState");
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
        {
            System.out.println("现在是横屏转竖屏");
        }else if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
        {
            System.out.println("现在是竖屏转横屏");
        }
    }
}

总结:因此在切换屏幕时会出现一些错误或bug,很有可能是设置android:configChanges属性值方式不准确,引起生命周期的改变,从而丢失数据。所以有以上可以看到在生命周期发生变化时,还会回调两个方法:在onStop之前会调用onSaveInstanceState(),我们可以在这里对Activity的状态和数据进行保存,在重新显示该Activity的onResume方法之前会调用onRestoreInstanceState()方法,我们可以在此方法中恢复之前保存的状态和数据。

当然我们也可以完全屏蔽掉Activity的切换屏幕的操作:

1、可以在xml中设置属性:

       android:screenOrientation="portrait" 始终以竖屏显示 
       android:screenOrientation="landscape" 始终以横屏显示

2、可以在代码中设置:

       Activity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);以竖屏显示                     

       Activity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);以横屏显示

五、Activity的异常情况时保存状态

Activity异常实在非人为主动结束Activity的行为。

(一)、异常的几种情况:

  • 资源系统配置

如横竖屏切换时,Activity可能会被销毁重建,或者设备语音发生变化,或者键盘发生变化时。如果不希望重启Activity,可以在清单文件Activity中设置configChanges,详情见上文的横竖屏切换。

  • 系统资源不足时

由于android自带GC回收机制,系统会在内存不足时,自动回收掉优先级低的进程,释放内存供优先级高的使用。

以下是android进程的优先级,从高到低依次列出:

  1. 前台进程(Foreground process)。它表明用户正在与该进程进行交互操作,android系统依据下面的条件来将一个进程标记为前台进程:

    一般情况下,不会有太多的前台进程。杀死前台进程是操作系统最后无可奈何的做法。当内存严重不足的时候,前台进程一样会被杀死。

    • 该进程持有一个用户正在与其交互的Activity(也就是这个activity的生命周期方法走到了onResume()方法)。
    • 该进程持有一个Service,并且这个Service与一个用户正在交互中的Activity进行绑定。
    • 该进程持有一个前台运行模式的Service(也就是这个Service调用了startForegroud()方法)。
    • 该进程持有一个正在执行生命周期方法(onCreate()、onStart()、onDestroy()等)的Service。
    • 该进程持有一个正在执行onReceive()方法的BroadcastReceiver。
  2. 可见进程(Visible process)。它表明虽然该进程没有持有任何前台组件,但是它还是能够影响到用户看得到的界面。android系统依据下面的条件将一个进程标记为可见进程:

    • 该进程持有一个非前台Activity,但这个Activity依然能被用户看到(也就是这个Activity调用了onPause()方法)。例如,当一个activity启动了一个对话框,这个activity就被对话框挡在后面。
    • 该进程持有一个与可见(或者前台)Activity绑定的Service。
  3. 服务进程(Service process)。除了符合前台进程和可见进程条件的Service,其它的Service都会被归类为服务进程。
  4. 后台进程(Background process)。持有不可见Activity(调用了onStop()方法)的进程即为后台进程。通常情况下都会有很多后台进程,当内存不足的时候,在所有的后台进程里面,会按照LRU(最近使用)规则,优先回收最长时间没有使用过的进程。
  5. 空进程(Empty process)。不持有任何活动组件的进程。保持这种进程只有一个目的,就是为了缓存,以便下一次启动该进程中的组件时能够更快响应。当资源紧张的时候,系统会平衡进程缓存和底层的内核缓存情况进行回收。

注意:

  • 如果一个进程同时满足以上5种中多个条件,那么系统会选满足条件的最高优先级作为此进程的优先级。
  • 如果一个进程为另外一个进程提供服务,那么这个进程的优先级不会低于享受服务的进程。

(二)、关于Activity状态保存,主要涉及两个方法:

下图为Activity文档中,对保存状态描述:

  •  onSaveInstanceState()-->保存数据:

需要注意,此方法只在需要保存状态是才会调用,也就是说用户显示关闭Activity时,表明不需要保存状态,则系统不会调用此方法。如果系统调用此方法一般会在Activity开始停止前(即在onStop()方法之前)调用,但有时也会在onPause()方法前调用。

        @Override
        protected void onSaveInstanceState(Bundle outState) {
            // TODO Auto-generated method stub
            super.onSaveInstanceState(outState);
            //保存数据
            outState.putString("message", "Hello!");
        }
  • onRestoreInstanceState()-->恢复数据

一般此方法会在新建Activity实例的onStart()方法后执行,并获取保存数据。

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    //恢复状态
    if(savedInstanceState!=null){
        String msg = savedInstanceState.getString("message");
        //设置这个数据到需要的地方
                
    }
}

参考:

https://www.cnblogs.com/KingSkull/p/6095062.html


猜你喜欢

转载自blog.csdn.net/wwp9527/article/details/82112955