全面了解 Activity

《全面了解 Activity》

Image.png

大家好,我叫石头

Activity是什么?

相信大家都知道Android中的4大组件(Activity活动,Service服务,ContentProvider内容提供者,BroadcastReceiver广播接收器),Activity是我们使用最多的也是最基本的组件,Activity提供窗口和用户进行交互.

Android中的activity全都归属于task管理(task是一个具有栈结构的容器),task是多个activity的集合,android默认情况会为每个App维持一个task来存放app的所有activity(当然这只是默认情况),task的默认name为该apppackagename(包名)

当然我们也可以在AndroidMainfest.xml中申明activity taskAffinity 属性来自定义task,但是不建议使用,因为如果其他app也申明了同样的task,那个app可能启动到你的activity,这样会带来各种安全问题(比如拿到你的Intent).

Activity的内部调用

上面我们介绍过了,系统是通过task(栈)的方式来管理activity的,当一个新的activity开始的时候,该activity会被放置在堆栈(back stack)的顶部,成为正在运行的活动,之前的activity始终保持低于它在堆栈,而不会出现在前台.

官方activity_lifecycle:

《全面了解 Activity》

activity

当我们打开一个新的activity实例的时候,系统会以此调用

onCreate() -> onStart() -> onResume() 然后开始running

activity在running的时候如果被覆盖(打开新的activity,或者被锁屏,但是它依然在前台运行,lost focus but is still visible),系统就会调用onPause();

onpause()方法中,我们通常会提交未保存的更改到持久化数据,停止动画和其他东西.但是我们要知道现在这个activity还是完全活着(它保存所有的状态和成员信息,并且保存到窗口管理器的连接)

  • 1.启动Activity:系统会先调用onCreate方法,然后调用onStart方法,最后调用onResumeActivity进入运行状态。
  • 2.当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。
  • 3.当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。
  • 4.当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。
  • 5.用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。
  • 6.当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。
  • 7.用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity

onSaveInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;(2)在用户改变屏幕方向时,此方法会被调用;(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState的调用顺序是在onPause之前。

onRestoreInstanceState:(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。onRestoreInstanceState的调用顺序是在onStart之后。

activity被回收的状态和信息保存和恢复过程

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if(savedInstanceState!=null){ //判断是否有以前的保存状态信息
             savedInstanceState.get("Key"); 
             }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
   @Override
protected void onSaveInstanceState(Bundle outState) {
    // TODO Auto-generated method stub
     //可能被回收内存前保存状态和信息,
       Bundle data = new Bundle(); 
       data.putString("key", "last words before be kill");
       outState.putAll(data);
    super.onSaveInstanceState(outState);
}
   @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
       if(savedInstanceState!=null){ //判断是否有以前的保存状态信息
             savedInstanceState.get("Key"); 
             }
    super.onRestoreInstanceState(savedInstanceState);
}
}

onSaveInstanceState()方法,在activity被回收之前调用,用来保存自己的状态信息,以便回收后重建时恢复数据(在onCreate()onRestoreInstanceState()中恢复).旋转屏幕重建activity会调用该方法,但其他情况在onRause()onStop()状态的activity不一定会调用,
下面是官方文档说明:

  One example of when onPause and onStop is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause is called and not onSaveInstanceState is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.

也就是说,系统灵活的来决定会不会调用该方法,但是如果要调用就一定发生在onStop方法之前,但不保证发生在onPase的前面还是后面.

onRestoreInstanceState()该方法在onstartonPostCreate之间调用,当然我们也可以在onCreat中恢复之前我们在onSaveInstanceState()中保存下来的数据,但是我们有时候需要在初始化布局完成之后再恢复数据,这是就可以在onRestoreInstanceState()中恢复数据.
onPostCreate():一般我们都没有实现这个方法,它的作用是在代码开始运行之前,调用系统做最后的初始化工作.

关于启动模式

启动模式是什么?

简单点说就是:定义activity实例与task的关联方式

为什么我们要定义启动模式呢?

为了实现默认启动(standard)模式之外的需求:

  • 让某个activity启动一个新的task(而不是被放入当前task)
  • 让activity启动时只调用已有的某个实例(而不是在back stack(之前我们有提到过哟) 顶创建一个新的实例)
  • 当用户离开task时只想保留根activity,而back stack中的其他activity都要清空.

怎样定义启动模式

定义启动模式的方法有2种:
  • 使用manifest文件定义
  • 使用Intent标志定义

使用manifest文件定义启动模式:
在 manifest 文件中activity声明时,利用 activity 元素的 launchMode 属性来设定 activity 与 task 的关系。

<activity ...... android:launchMode="standard" >
           .......
</activity>

注意: 你用 launchMode 属性为 activity 设置的模式可以被启动 activity 的 intent 标志所覆盖,代码的优先级最高。

现在我们知道了怎么定义启动模式了,但是有哪些启动模式呢?

  • standard (默认模式)
    当通过这种模式启动activity时,Android总会为目标 Activity创建一个新的实例(之前有过也会重新创建),并将该Activity添加到当前Task栈中。这种方式不会启动新的Task,只是将新的 Activity添加到原有的Task中。

《全面了解 Activity》

  • singleTop
    该模式和standard模式基本一致,但有一点不同:当将要被启动的Activity已经位于Task栈顶时,系统不会重新创建目标Activity实例,而是直接复用Task栈顶的Activity。

《全面了解 Activity》

  • singleTask
    Activity在同一个Task内只有一个实例。
    如果将要启动的Activity不存在,那么系统将会创建该实例,并将其加入Task栈顶; 

  如果将要启动的Activity已存在,且存在栈顶,直接复用Task栈顶的Activity。 

  如果Activity存在但是没有位于栈顶,那么此时系统会把位于该Activity上面的所有其他Activity全部移出Task,从而使得该目标Activity位于栈顶。

《全面了解 Activity》

  • singleInstance
     无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例且会用一个全新的Task栈来装载该Activity实例(全局单例).

  如果将要启动的Activity不存在,那么系统将会先创建一个全新的Task,再创建目标Activity实例并将该Activity实例放入此全新的Task中。

  如果将要启动的Activity已存在,那么无论它位于哪个应用程序,哪个Task中;系统都会把该Activity所在的Task转到前台,从而使该Activity显示出来。

和”singleTask”类似,唯一不同的是系统不会在这个activity的实例所在的task中启动任何其他activity。

  这个activity的实例永远是这个task中的唯一一个成员,这个activity启动的任何其他activity都将在另外的task中打开。

《全面了解 Activity》

使用Intent标识定义启动模式:

  • FLAG_ACTIVITY_NEW_TASK
    和之前讨论过的”singleTask”相同,在新的task中启动activity,如果一个你需要的activity的task已经存在,则将它推向前台,恢复其上一个状态,它通过onNewIntent()收到这个新的intent。
  • FLAG_ACTIVITY_SINGLE_TOP
    和”singleTop”行为相同,如果被启动的activity是当前顶部的activity,则已经存在的实例收到 onNewIntent()
    ,而不是新建实例。

  • FLAG_ACTIVITY_CLEAR_TOP
    如果被启动的activity已经在当前task运行,不创建它的新实例,而是销毁在它之上的其他所有activities,然后通过 onNewIntent()
    传递一个新的intent给这个恢复了的activity。
      这个行为在 launchMode 中没有对应的属性值。
      注意,如果activity的启动模式是”standard”,它自己也将被移除,然后一个新的实例将被启动。
      这是因为当启动模式是”standard”时,为了接收新的intent必须创建新的实例。

处理affinities

Affinity指示了activity更倾向于属于哪个task。
  默认情况下,同一个应用的activities倾向于在同一个task中。你可以通过<activity>标签中的 taskAffinity 来修改这种行为。
  详细内容请查看:API Guides: Tasks and Back Stack
  developer.android.com/guide/compo…

开启一个task

你可以通过给activity一个intent filter(action是”android.intent.action.MAIN”,category是”android.intent.category.LAUNCHER”),让这个activity是一个task的进入点。

  如下:

<activity ... >
    <intent-filter ... >
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

一个这样的intent filter会使得这个activity的icon和label显示在程序启动处,提供了一种方法,使得用户可以启动这个activity,当它启动后,用户也可以通过它来返回到这个task。
  第二个能力是很重要的:用户必须能够离开一个task,然后通过activity launcher返回到它。
  因为这个原因,两个让activity永远实例化一个task的启动模式:”singleTask” 和”singleInstance”,应该仅在activity有一个 ACTION_MAINCATEGORY_LAUNCHER filter的时候用它们。

至此,相信大家对Activity有了更深的了解了吧~~~
    原文作者:Android
    原文地址: https://juejin.im/entry/589847f7128fe10058ebd803
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞