Android四大组件之Activity

迷茫,是青春最真实的状态;但奋斗,才是青春的主基调;努力是打败焦虑的绝好方法!

安卓四大组件除了BroadcastReceiver外,都要在manifest中注册,BroadcastReceiver可以在manifest中注册,也可以通过代码动态注册;除了ContentProvider不用借助Intent,其他都要借助。

生命周期

典型情况下的生命周期分析

  • onCreate():Activity正在被创建。
  • onRestart():Activity正在重新启动。
  • onStart():Activity正在被启动;当前状态表示已经可见,但是无法交互,还没有显示在前台。
  • onResume():Activity已经可见了,并且出现在前台并开始活动。表示Activity已经显示在前台,并且可以交互了。
  • onPause():Activity正在停止,前端不可显示,但是还在后台运行。
  • onStop():Activity即将停止。
    onPause()和onStop()两个方法被执行的时候都不能做耗时操作。
  • onDestroy():Activity即将被销毁,这是生命周期最后一个回调,释放资源和内存。

onStart和onStop是从Activity是否可见来回调的。
onResume和onPause是从Activity是否位于前台来回调的。

图片来与网络
针对上图,再附加一下具体说明,但图中容易理解的不再赘述。

  • 当前已有一个Activity时,当用户打开新的Activity或者切换到桌面时,回调onPause -> onStop。
    即当前Activity已经看不见,因为切换到了桌面,所以当前Activity不可见,由于onPause关键在于是否位于前台,onStop关键在于是否可见,所以要执行到onStop才可以。
  • 有一种特殊情况,如果新的Activity采用了透明主题,那么当前的Activity不会回调onStop方法。
    是新打开的Activity是透明主题,不是原来的,所以原来那个Activity位于当前透明主题的Activity的下方,根据Activity栈,可以看见原来的Activity,但是无法和用户进行交互,所以是可见但是不位于前台,所以onStop不执行。
  • 当用户按back键回退时,从onPause一直回调至onDestroy。
    back键是返回上级菜单,即返回上一个Activity,所以当前Activity会被销毁,执行至onDestroy;home键是返回主菜单,就好像桌面一样,只执行到onStop。

异常情况下的生命周期分析

异常情况下Activity的生命周期

  1. 资源相关的系统配置发生改变导致Activity被杀死并重新创建。
    资源配置发生改变,比如屏幕的朝向(横竖屏),Activity会被销毁并且重新创建。
    由于在异常情况下终止的,系统调用onSaveInstanceState保存当前Activity的状态和数据,并将其封装为Bundle对象,在后面调用onRestoreInstanceState方法时作为参数传入,这个方法在onStop之前,并且只有在Activity异常终止的情况下才会被调用。
    重新创建后,系统在onCreate新建Activity之后,在onStart之后调用onRestoreInstanceState来恢复数据。这个方法也只有在异常终止恢复数据时才会被调用,不然不会调用这个方法,而是正常创建新的Activity。
  2. 系统内存不足导致低优先级的Activity被杀死。
    Activity优先级:
    • 前台Activity——正在和用户交互的Activity,优先级最高。
    • 可见但是非前台Activity——例如弹出一个对话框,使Activity位于后台,无法和用户直接交互,优先级较高。
    • 后台Activity——已经被暂停的Activity,如执行了onStop的,优先级最低。
      当内存不够时,按照上述优先级进行销毁,在后续通过onSaveInstanceState和onRestoreInstanceState方法来恢复使用。

想要不重新创建Activity也是有方法的,在系统资源配置中设置configChanges的属性即可。

启动模式

如何指定Activity的启动模式?

  1. 在AndroidMenifest中使用launchMode属性即可。
android:launchMode="singleTask"
  1. 通过Intent来设置标志位启动。
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  • 当两种方式同时存在时,以第二种为主,优先级高。
  • 第一种方式无法直接为Activity指定FLAG_ACTIVITY_CLEAR_TOP标识
  • 第二种方式无法为Activity直接设定singleInstance模式。

standard(标准模式)

标准模式是系统的默认启动模式,每次启动一个Activity都会建立一个新的实例,不在乎这个实例是否存在。这是一种多实例的实现,一个任务栈可以有多个实例,一个实例也可以在多个任务栈

启动一个Activity的必须是一个Activity,否则会报错,因为Activity一定有一个栈,被启动的Activity会进入启动它的Activity的任务栈中,但是如果启动它的对象没有任务栈,就会出现错误。防止其发生错误也有方法,就是为将要启动的Activity加一个标志位,但是这时已经不能算是一个真正的标准模式启动了。

singleTop(栈顶复用模式)

栈顶复用模式很简单,就如同它的名字一样,就是把位于栈顶的Activity复用

  1. 如果在一个任务栈中已存在待启动的Activity并且其位于栈顶,那么它不会被重新创建一个新的实例,即上面生命周期的onCreate和onStart不会被调用,而是调用onNewIntent方法(这个方法现在我也不了解),这个方法是用来取出当前请求的信息的。
  2. 如果这个Activity存在但是不位于栈顶,那么还是需要重新创建实例并压入栈内。

singleTask(栈内复用模式)

栈内复用模式是Activity启动模式中最复杂的一个模式,是一个单实例模式。
4. 当一个Activity以这个模式启动时,系统会寻找它要的任务栈,如果不存在这个栈,会创建这个栈并且实例化这个Activity并将其压入栈内。
5. 如果这个栈存在,但是当中没有待启动的Activity,则将Activity实例化并压入栈内。
6. 如果栈存在,并且其中有了待启动的Activity,位于栈顶,则是栈顶复用模式;不位于栈顶,则将其移到栈顶,调用onNewIntent方法,但是在其上的Activity全部要出栈。因为singleTask默认具有clearTop效果

说到singleTask模式还要说一个参数:TaskAffinity。
可翻译为任务相关性,就是用来存Activity所在的任务栈的名字

  • 这个属性值不能和包名相同,否则相当于没有指定。
  • 这个属性要和singleTask模式或者allowTaskReparenting属性配对使用,其他情况下无意义。

举个例子,方便理解,allowTaskReparenting属性我也不清楚意思,但是当一个Activity的这个属性值为true时,好像就是允许Activity的迁移,有点像小狗认主人。
假设应用A启动了应用B的一个Activity C,B的allowTaskReparenting属性值为true,当A启动C时,C跑到A的任务栈里了,但是当B启动时,由于C的TaskAffinity的属性值为B的任务栈,并且其allowTaskRepareting属性为true,所以C又回到了B的任务栈中。
简单来说,就是你在路边捡到一只小狗,你养了几天,以为小狗是自己的了,然后它主人来了,小狗还是跟着主人走了。(此例子参考了一个博客)

singleInstance(单实例模式)
单实例模式是一种加强的栈内复用模式,除了具有singleTask模式的所有特性外,还有独特的一点。即具有这种启动模式的Activity只能单独的在一个任务栈中,这个任务栈也只能有其一个Activity,也就是多了一个任务栈

应用场景

  • Standard:非以下特殊场景的普通Activity

  • SingleTop:APP接收到多条推送消息,点开不同消息,均由同一实例展示。singleTop适合接收推送通知的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。

  • SingleTask:应用APP的主界面(Fragment的containerActivity)。singleTask适合作为程序入口点。例如淘宝的主界面,在淘宝陆续打开商品搜索界面、商品详细界面、订单界面、付款成功界面后,在付款成功界面一键返回主界面。

  • SingleInstance:如APP经常调用的拨打电话、系统通讯录、系统Launcher、锁屏键、来电显示等系统应用。singleInstance适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。

工作原理

Activity的启动

Intent intent = new Intent(this,TestActivity.class);
startActivity(intent);

Activty的启动过程中的方法调用过程

  1. Activity的startActivity
  2. startActivityForResult
  3. Instrumentation.execStartActivity
  4. ActivityManagerNative.getDefault().startActivity
  5. AMS.startActivity
  6. startActivityAsUser
  7. ActivityStackSupervisor.startActivityMayWait
  8. startActivityLocked
  9. startstartActivityUncheckedLocked
  10. ActivityStack.resumeTopActivitiesLocked
  11. ActivityStack.resumeTopActivityInnerLocked
  12. startSpecificActivityLocked
  13. realStartActivityLocked
  14. app.thread.scheduleLaunchActivity
  15. ApplicationThead.scheduleLaunchActivity
  16. handleLaunchActivity
  17. ActivityThread.performLaunchActivity

1到2

虽然startActivity有很多重载方式,但它们最终都会调用startActivityForResult方法。

2到3

startActivityForResult方法中有如下代码:
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this,mMainThread.getApplicationThread(),mToken,this,intent,requestCode,options);
注意:
mMainThread.getApplicationThread()这个参数,它的类型是ApplicationThread,ApplicationThread是ActivityThread的一个内部类。

3到4
execStartActivity 的代码如下:

int result = ActivityManagerNative.getDefault()
   .startActivity(whoThread,who.getBasePackageName(),intent,
           intent.resolveTypeIfNeeded(who.getContentResolver()),
           token,target != null ? target.mEmbeddedID : null,
           requestCode, 0, null, options);
checkStartActivityResult(result,intent);

由上述代码可见,Activity的真正实现由ActivityManagerNative.getDefault()的startActivity方法来完成。
checkStartActivityResult的作用:检查启动的Activity的结果。无法启动时,抛出一个异常。

4到5

ActivityManagerService(AMS) extends ActivityManagerNative
ActivityManagerNative extends Binder implements IActivityManager(Binder接口)
所以AMS也是一个Binder,是IActivityManager的具体实现。
由于ActivityManagerNative.getDefault()是一个IActivityManager类型的Binder对象,所以其具体实现就是AMS。即ActivityManagerNative.getDefault()就是AMS,所以启动过程转移到AMS的startActivity中。

5到6

public final int startActivity(...){
       return startActivityAsUser(...);
      }

6到7

public final int startActivityAsUser(...){
    enforceNotIsolatedCaller("startActivity");
    userId = handleIncomingUser(...);
    return mStackSupervisor.startActivityMayWait(...);
    }

7到13

这一段位置Activity的启动过程在ActivityStackSupervisor和ActivityStack之间传递。以下图进行描述。
在这里插入图片描述

13到14
realStartActivityLocked中有一段代码:

app.thread.scheduleLaunchActivity(...);

14到15

app.thread 的类型是 IApplicationThread,IApplicationThread是一个接口,它继承IInterface接口,所以它是一个Binder类型的接口。
从接口方法命名看出,这个接口完成了大量和Activity以及Service启动/停止相关的功能。
IApplicationThread的实现者是ActivityThread的内部类ApplicationThread。所以转移到了ApplicationThread的scheduleLaunchActivity方法。

15到16

ApplicationThread的scheduleLaunchActivity的实现很简单。

  • 发送一个启动Activity的消息给Handler处理
    ActivityClientRecord r = new ActivityClientRecord(); sendMessage(H.LAUNCH_ACTIVITY,r);

接着Handler处理消息,主线程中默认Handler为H。

private class H extends Handler{
  .....
  .....
  public void handleMessage(Message msg){
      ...
      switch(msg.what){
         case LAUNCH_ACTIVITY:{
              ...
              handleLaunchActivity(r,null);
         }
         break;
         ...
      }
  ...
  }
}   

16到17

private void handleLaunchActivity(...){
   ...
   Activity a = performLaunchActivity(...);
   if(...){
        ...
        handleResumeActivity(...);
        ...
   }
   ...
}

由上述代码可见,performLaunchActivity方法最终完成了Activity对象的创建和启动过程,并且ActivityThread通过handleResumeActivity方法来调用被启动Activity的onResume这一生命周期方法。


performLaunchActivity主要完成的事件

  • 从ActivityClientRecord中获取待启动的Activity的组件信息
  • 通过Instrumentation的newActivity方法使用类加载器创建Activity对象
  • 通过LoadedApk的makeApplication方法来尝试创建Application对象
  • 创建ContextImpl对象并通过Activity的attach方法来完成一些重要数据的初始化
  • 调用Activity的onCreate方法。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值