Android四大组件——Activity

2021-02-08  本文已影响0人  peter_RD_nj

Activity

Activity是一种展示型组件,用于向用户直接地展示一个界面,并且可以接受用户的输入信息并进行交互。从代码的继承关系可以看出,Activity可以理解为一个带Theme的Context。

Activity

Activity生命周期

Activity生命周期

注:是否能跟用户进行交互来区分Activity是在前台还是后台;UI是否显示来区分是否可见。onStart 和onStop 从是 否可见来回调的;onResume和onPause 从是否在前台来回调的。可见但非前台的常见例子:Activity弹出一个dialog,Activity可见但不可以和用户交互。

当资源相关的系统配置发生改变及系统内存不足时,Activity就可能被杀死。

当系统配置发生改变后,Activity会被销毁再重建,其onPause、onStop和onDestroy均会被调用。同时,Activity有可能被杀死的时候系统会调用onSaveInstanceState来保存当前Activity的状态。该方法在onStop之前调用,与onPause没有先后关系。Activity被重新创建时系统会调用onRestoreInstanceState方法,在onStart后被调用。系统只会在Activity即将被销毁并且有机会重新显示的情况下才会去调用onSaveInstanceState方法。
同Activity一样,每个View都有onSaveInstanceState和onRestoreInstanceState方法,可以查看相关源码了解系统可以自动为每个View恢复哪些数据。保存和恢复View层次结构,系统工作流程:当Activity被意外终止,Activity首先会调用onSaveInstanceState去保存数据,然后Activity会委托Window去保存数据,接着Window在委托它上面的顶级容器去保存数据(DecorView)。最后顶级容器在去一一通知他的子元素来保存数据。这个过程是一个典型的委托思想,上层委托下层、父容器委托子元素去做一件事情。View的绘制过程、事件的分发等都是采用类似思想。

Activity优先级由高到低:前台Activity>可见但非前台>后台不可见Activity。当系统内存不足时,就会根据上述优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceState和onRestoreInstanceState方法来备份和恢复数据。如果一个进程没有四大组件在执行,那么这个进程将很快被系统杀死。我们可以把后台工作放在service中执行,以保证具有一定的优先级,不会轻易的被系统杀死。

Google源码对onSaveInstanceState方法的注释中指出——只要Activity有可能被杀掉就会调用onSaveInstanceState方法来保存瞬时数据,比如旋转屏幕、按下home键、menu键或是启动了另一个Activity等场景都会触发onSaveInstanceState方法的调用。

下面通过打印的log来分析一下不同场景下Activity生命周期相关方法调用的顺序。

03-09 00:31:31.755 1549-1549/com.android.peter.activitydemo D/Activity: onCreate
03-09 00:31:31.759 1549-1549/com.android.peter.activitydemo D/Activity: onStart
03-09 00:31:31.770 1549-1549/com.android.peter.activitydemo D/Activity: onResume
03-09 00:31:59.068 1549-1549/com.android.peter.activitydemo D/Activity: onPause
03-09 00:31:59.099 1549-1549/com.android.peter.activitydemo D/Activity: onSaveInstanceState
03-09 00:31:59.102 1549-1549/com.android.peter.activitydemo D/Activity: onStop
03-09 00:32:35.716 1549-1549/com.android.peter.activitydemo D/Activity: onRestart
03-09 00:32:35.717 1549-1549/com.android.peter.activitydemo D/Activity: onStart
03-09 00:32:35.719 1549-1549/com.android.peter.activitydemo D/Activity: onResume
03-09 00:33:54.916 1549-1549/com.android.peter.activitydemo D/Activity: onPause
03-09 00:33:55.322 1549-1549/com.android.peter.activitydemo D/Activity: onStop
03-09 00:33:55.325 1549-1549/com.android.peter.activitydemo D/Activity: onDestroy
03-09 00:34:27.845 1549-1549/com.android.peter.activitydemo D/Activity: onPause
03-09 00:34:27.847 1549-1549/com.android.peter.activitydemo D/Activity: onSaveInstanceState    //跟onPause方法没有明确的先后关系,在onStop之前被调用
03-09 00:34:27.851 1549-1549/com.android.peter.activitydemo D/Activity: onStop
03-09 00:34:27.853 1549-1549/com.android.peter.activitydemo D/Activity: onDestroy
03-09 00:34:28.066 1549-1549/com.android.peter.activitydemo D/Activity: onCreate
03-09 00:34:28.069 1549-1549/com.android.peter.activitydemo D/Activity: onStart
03-09 00:34:28.070 1549-1549/com.android.peter.activitydemo D/Activity: onRestoreInstanceState    //在onStart之后被调用
03-09 00:34:28.077 1549-1549/com.android.peter.activitydemo D/Activity: onResume
05-03 16:35:35.592 25819-25819/com.android.peter.handlerdemo D/MainActivity: onCreate
05-03 16:35:35.596 25819-25819/com.android.peter.handlerdemo D/MainActivity: onStart
05-03 16:35:35.603 25819-25819/com.android.peter.handlerdemo D/MainActivity: onResume
05-03 16:35:35.605 25819-25819/com.android.peter.handlerdemo D/MainActivity: finish
05-03 16:35:35.623 25819-25819/com.android.peter.handlerdemo D/MainActivity: onPause
05-03 16:35:36.380 25819-25819/com.android.peter.handlerdemo D/MainActivity: onStop
05-03 16:35:36.382 25819-25819/com.android.peter.handlerdemo D/MainActivity: onDestroy

Activity启动模式

Activity有四种启动模式:

Activity常用的Flag

FLAG_ACTIVITY_NEW_TASK:为Activity指定“singletask”模式。
FLAG_ACTIVITY_SINGLE_TOP:为Activity指定“singletop”模式。 FLAG_ACTIVITY_CLEAR_TOP:和FLAG_ACTIVITY_NEW_TASK配对使用,在同一任务栈中所有位于它上面的Activity都要出栈。
FLAG_ACTIVITY_NO_HISTORY:使用这个flag启动Activity不会被压入栈中。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:启动的Activity不会出现在recentTask中,等同于在AndroidManifest.xml中Activity的属性 android:excludeFromRecents="true"。

Activity保存临时数据和状态

系统在Activity即将被销毁并且有机会重新显示的情况下才会去调用onSaveInstanceState方法来保存临时数据和状态。该方法在onStop之前调用,与onPause没有先后关系。Activity被重新创建时可以从onCreate方法或是onRestoreInstanceState方法中获得之前保存的临时数据和状态。

有以下几个常见的场景:
1、当用户按下HOME键时。
2、长按HOME键,选择运行其他的程序时。
3、按下电源按键(关闭屏幕显示)时。
4、从activity A中启动一个新的activity B时。
5、屏幕方向切换时,例如从竖屏切换到横屏时。

下面以旋转屏幕为例看一下Activity各个方法的调用情况。主要逻辑代码如下:

public class MainActivity extends AppCompatActivity {
    private final static String TAG = "Activity";
    private final static Boolean DEBUG_ACTIVITY_PERIOD = true;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onCreate");
        if(savedInstanceState != null) {
            Log.d(TAG,"onCreate " + savedInstanceState.getString("msg","null"));
        }
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onRestart");
    }

    @Override
    protected void onStart() {
        super.onStart();
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onDestroy");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onSaveInstanceState");
        outState.putString("msg","Android");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onRestoreInstanceState");
        if(savedInstanceState != null) {
            Log.d(TAG,"onRestoreInstanceState " + savedInstanceState.getString("msg","null"));
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if(DEBUG_ACTIVITY_PERIOD) Log.d(TAG,"onConfigurationChanged");
    }
}

上面示例的代码逻辑很简单,就是在onSaveInstanceState方法被调用的时候保存了一个字符串“msg:Android”到Bundle实例里面去,在onCreate和onRestoreInstanceState把这个字符串从Bundle实例里面取出来。旋转后截取的log如下:

03-09 18:24:14.113 8705-8705/com.android.peter.activitydemo D/Activity: onPause
03-09 18:24:14.116 8705-8705/com.android.peter.activitydemo D/Activity: onSaveInstanceState
03-09 18:24:14.127 8705-8705/com.android.peter.activitydemo D/Activity: onStop
03-09 18:24:14.129 8705-8705/com.android.peter.activitydemo D/Activity: onDestroy
03-09 18:24:14.269 8705-8705/com.android.peter.activitydemo D/Activity: onCreate
03-09 18:24:14.269 8705-8705/com.android.peter.activitydemo D/Activity: onCreate Android
03-09 18:24:14.272 8705-8705/com.android.peter.activitydemo D/Activity: onStart
03-09 18:24:14.273 8705-8705/com.android.peter.activitydemo D/Activity: onRestoreInstanceState
03-09 18:24:14.273 8705-8705/com.android.peter.activitydemo D/Activity: onRestoreInstanceState Android
03-09 18:24:14.281 8705-8705/com.android.peter.activitydemo D/Activity: onResume

总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。另外,使用过程中还要需要注意以下几点:
1.布局中的每一个View默认实现了onSaveInstanceState()方法,这样的话,这个UI的任何改变都会自动地存储和在activity重新创建的时候自动地恢复。但是这种情况只有在你为这个UI提供了唯一的ID之后才起作用,如果没有提供ID,app将不会存储它的状态。
2.由于默认的onSaveInstanceState()方法的实现帮助UI存储它的状态,所以如果你需要覆盖这个方法去存储额外的状态信息,你应该在执行任何代码之前都调用父类的onSaveInstanceState()方法(super.onSaveInstanceState())。 既然有现成的可用,那么我们到底还要不要自己实现onSaveInstanceState()?这得看情况了,如果你自己的派生类中有变量影响到UI或你程序的行为,当然就要把这个变量也保存了,那么就需要自己实现,否则就不需要。
3.由于onSaveInstanceState()方法调用的不确定性,你应该只使用这个方法去记录activity的瞬间状态(UI的状态),不应该用这个方法去存储持久化数据。当用户离开这个activity的时候应该在onPause()方法中存储持久化数据(例如应该被存储到数据库中的数据)。
4.onSaveInstanceState()如果被调用,这个方法会在onStop()前被触发,但系统并不保证是否在onPause()之前或者之后触发。

Activity其他的常用回调方法

菜单(Options menu)相关

Window相关

按键(Key)相关

其他

上一篇 下一篇

猜你喜欢

热点阅读