安卓Activity生命周期相关

安卓Activity生命周期相关

activity作为安卓四大组件之一,是我们在开发中使用的最频繁的组件之一。
在这里就个人所了解的一些东西,和大家分享一下下。有错误之处,多多指正。

典型生命周期

首先,activity的生命周期(从创建到被垃圾回收过程中一定会执行的方法就叫做生命周期方法)这里就放上官方文档上最经典的图吧。
activity生命周期
大家对这幅图肯定也无比熟悉了。
一个正常典型情况下的activity启动,会经历如下生命周期:
- onCreate:activity创建时,会首先启动这个方法。一般这个方法中,我们会做一些初始化工作。
- onDestroy:activity即将被销毁时调用的方法,是生命周期的最后一个方法。一般,我们会做一些回收工作和最终的资源释放,或者是保存一些未保存的内容(比如保存信息为草稿等)
- onStart:activity正在被启动,即将开始时,这个时候activity界面可见,但是无法和用户交互,activity还在后台
- onStop:activity界面不可见时调用的方法。可以做些微重量级的回收工作。
- onResume:activity获取焦点时的方法,已经出现在前台并且开始活动。
- onResume:activity获取焦点时的方法,已经出现在前台并且开始活动。
- onPause:activity失去焦点时调用的方法,但是此时activity可见。这里可以做一些存储数据、停止动画的工作,但是不能太过耗时。因为一个新的activity的启动,onPause必须先执行完,新Activity的onResume才会调用
- onRestart:activity在重新启动。一般是用户点击home键回到桌面或者跳到新的activity时,接着用户又重新回到这个activity,界面由不可见变为可见,执行onRestart-onStart-onResume


在图中,我们发现这样的一段话[Another activity comes in front of the activity][6]调用时会首先执行onPause方法。
为什么呢?从源码角度上大概是这个流程:
首先,启动activity的请求会由Instrumentation(可以理解为一种没有图形界面的,具有启动能力的,用于监控其他类(用Target Package声明)的工具类)来处理, 它会通过代理对象binder向ActivityManagerService(简称AMS,内部维护着一个ActivityStack)发送请求,AMS通过ActivityThread去同步activity的状态。新的activity启动时,会调用ActivityStack中的resumeTopActivityInnerLocked方法,使栈顶的activity需要先onPause变为后台后,新的activity才会被启动。
这也是为什么官方文档中对onPause的说明是,不能在onPause中做重量级的操作。
代码测试如下,其实很简单,当点击第一个activity的按钮时,会跳转到第二个activity(透明的主题)。当开启第二个activity时,会发现打印的log如下:
这里写图片描述
这里因为第二个activity是透明的主题,第一个activity虽然失去了焦点,不在前台,但仍处于可见状态,所以不会执行onStop方法。

异常情况下的生命周期

当资源相关的系统配置发生改变或者系统内存不足时,activity可能会被杀死。


譬如当前activity处于竖屏状态,如果旋转屏幕,由于系统配置发生了改变,在默认情况下,activity就会被销毁并且重新创建。其onPause、onStop、onDestroy都会被调用,系统还会调用onSaveInstanceState来保存当前activity的状态。这个方法在onStop之前调用,正常情况下系统不会调用这个方法,只有在被异常终止的情况下才会调用。当activity被重新创建后,将onSaveInstanceState保存的Bundle对象传递给onRestoreInstanceState和onCreate方法。如果被重建了,我们就可以通过bundle对象恢复之前的数据。会在onStart之后调用onRestoreInstanceState。
这样当异常情况下需要重新创建时,系统会默认为我们保存当前activity的视图结构,并且在activity重启后为每个View恢复数据。需要注意的是,系统只恢复那些被开发者指定过id的控件,如果没有为控件指定id,则系统就无法恢复了。
我们可以通过代码测试一下。首先当前的EditText控件并没有设置id,当输入内容后反转屏幕,EditText并未恢复其数据。
这里写图片描述

当设置id后,EditText才会恢复其数据。为了测试,自定义了一个EditText重写了其setText方法。

@override
public void setText(CharSequence text,BufferType type){
    super.setText(text,type);
    if(text.toString.equals("air")){
        throw new RuntimeException("----air---");
    }
}

首先,在文本输入框内,输入air,当屏幕反转后,activity恢复EditText数据时调用setText方法,会抛出异常。异常如下。
这里写图片描述
这里可以看出一个工作流程:首先Activity被意外终止时,Activity会调用onSavedInstanceState去保存数据,当需要恢复数据时,Activity会委托Window去恢复数据,接着Window再委托它上面的顶级容器去恢复数据,顶层容器是一个ViewGroup.最后顶层容器再去一一通知它的子元素来恢复数据,这样整个数据恢复过程就完成了,可以发现,这是一种典型的委托思想,上层委托下层,父容器委托子容器去处理一些事情。安卓中View的绘制机制、事件分发都是采用了类似的思想。
通过查看源码,我们不难得知,只有设置了id,才会调用view的onRestoreInstanceState方法去恢复数据。

protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
        if (mID != NO_ID) {//只有设置了id,才会去调用恢复状态的方法
            Parcelable state = container.get(mID);
            if (state != null) {
                // Log.i("View", "Restoreing #" + Integer.toHexString(mID)
                // + ": " + state);
                mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
                onRestoreInstanceState(state);
                if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                    throw new IllegalStateException(
                            "Derived class did not call super.onRestoreInstanceState()");
                }
            }
        }
    }

而当前的editText恢复数据时,会调用setText方法,发现反转前输入的文本为air时,抛出异常。

@Override
    public void onRestoreInstanceState(Parcelable state) {//恢复状态
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState)state;
        super.onRestoreInstanceState(ss.getSuperState());

        // XXX restore buffer type too, as well as lots of other stuff
        if (ss.text != null) {
            setText(ss.text);//会调用setText方法
        }

        if (ss.selStart >= 0 && ss.selEnd >= 0) {
            if (mText instanceof Spannable) {
                int len = mText.length();

                if (ss.selStart > len || ss.selEnd > len) {
                    String restored = "";

                    if (ss.text != null) {
                        restored = "(restored) ";
                    }

                    Log.e(LOG_TAG, "Saved cursor position " + ss.selStart +
                          "/" + ss.selEnd + " out of range for " + restored +
                          "text " + mText);
                } else {
                    Selection.setSelection((Spannable) mText, ss.selStart, ss.selEnd);

                    if (ss.frozenWithFocus) {
                        createEditorIfNeeded();
                        mEditor.mFrozenWithFocus = true;
                    }
                }
            }
        }

既然系统配置发生改变后,activity会被重新创建。那么,当某项内容发生改变后,我们不想系统重新创建Activity,可以给Activity指定configChanges属性。当屏幕旋转时,我们可以配置android:configChanges=”orientation”。如果想指定多个值,可以用“|”连接起来,例如android:configChanges=”orientation|keyboardHidden”。
系统配置中所包含的项目是很多,我们可以自行查找这些配置的意义,但是常用的一般有locale(设备本地位置发生改变),orientation(屏幕方向发生改变),keyboardHidden(键盘类型发生改变),screenSize(屏幕尺寸发生改变),其他很少使用。
screenSize和smallScreenSize比较特殊,他们的行为和编译选项有关,和运行环境无关。只有编译选项中minSdkVersion和TargetVersion有一项大于API13时,即4.0以后,会导致activity重启,需要加上screenSize。
如果配置了android:screenOrientation属性,则会使android:configChanges=”orientation”失效


进程的优先级:
* Foreground process

前台进程: 用户正在操作的应用程序所在的进程就是前台进程

  • Visible process

    可视进程: 用户已经不能操作这个应用程序了,但是界面用户仍然可以看到

  • Service process

    服务进程: 应用程序有一个服务代码正在运行

  • Background process

    后台进程: 应用程序有界面,但是界面被用户最小化(home)

  • Empty process

    空进程: 应用程序没有任何运行的Activity,service.

前台进程>可视进程>服务进程>后台进程>空进程
当系统内存不足时,系统就会按照上述的优先级顺序选择杀死Activity所在的进程,并在后续通过onSaveInstanceState缓存数据和onRestoreInstanceState恢复数据。
如果一个进程中没有四大组件在执行,那么这个进程将很快被杀死,因此,一些后台工作不适合脱离了四大组件工作,比较好的方法是将后台工作放入Service中从而保证进程有一定的优先级,这样就不会轻易的被系统杀死。
Over。

[暮春者,春服既成,冠者五六人,童子六七人,浴乎沂,风乎舞雩,咏而归][6]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值