Android四大组件--Activity详解(二)

1、Task 和 启动模式

Task

在 SDK中关于Task,有一个很好的比方,说,Task就相当于应用(application)的概念。在开发人员眼中,开发一个Android程序,是做一个个独门独户的组件,但对于一般用户而言,它们感知到的,只是一个运行起来的整体应用,这个整体背后,就是Task。 Task,简单的说,就是一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前后驱关联,新加入的Activity组件,位于栈顶,并仅有在栈顶的Activity,才会有机会与用户进行交互。而当栈顶的 Activity完成使命退出的时候,Task会将其退栈,并让下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多 Activity,Task结束。

在Manifest里可以配置Activity的进程,我们用process这个属性可以指定Activity的进程。每个任务栈都有一个ID,我们可以在代码中用getTaskId()可以指定当前Activity属于哪个Task,我们会发现只要是同一个应用的Activity它们即使在不同的进程但Task仍是同一个。

我们可以通过adb命令获取当前显示的任务栈有多少个Activity被启动了。

adb shell dumpsys activity

在Running Activities中能看到我们任务栈中的activity。

启动模式

LaunchMode同样是Manifest中为Activity设置的属性,Android给我们提供的LaunchMode有四种属性:

standard(默认):系统去启动一个Activity,即便是已经启动了一个同名的Activity,也会重新创建一个新的Activity。所以启用这种模式,一个应用可能会多个相同的Activity。

我们来为MainActivity增加一个Button,点击Button就跳转到MainActivity:

public void click2(View v) {
    Intent intent = new Intent(MainActivity.this, MainActivity.class);
    startActivity(intent);
}

从图中可知,不改变LaunchMode的值,则无论是否存在这个Activity都会重新创建一个新的。

singleTop:与standard有一些区别,例如现在任务栈中Activity顺序为A-B-C-D,D在栈顶,如果还要启动D这个Activity,则会调用自己的onNewIntent()方法,不会调用onCreate(),不会重新创建新的实例。但如果当前是C在栈顶,则即使栈中有D,也还是会重新创建。

singleTask:启用该模式,则一个Task中只允许一个实例存在,与singleTop不同的就是无论是不是在栈顶,只要在栈中就不会重新创建,并且将在这个Activity之上的所有Activity销毁掉。

现在我将MainActivity的LaunchMode设置为SingleTask,并为SecondActivity添加个能跳转到MainActivity的Button,在它们两个的onCreate(),onDestroy(),onNewIntent()方法添加log。我们运行程序看看。

按照我的操作,调用Activity的顺序为MainActivity—SecondActivity—MainActivity,因为MainActivity的LaunchMode为singleTask,所以MainActivity没有重新创建一个而是调用了栈中存在的,但因为在SecondActivity中调用了MainActivity,它们在栈中的顺序为MainActivity—SecondActivity,所有把MainActivity之上的所有Activity也就是SecondActivity销毁了,所以最后打印了在SecondActivity中onDestroy()方法的log。

singleInstance:与singleTask一样也是单实例的,但是它们的不同也是很明显的,如果我们把一个Activity设置为singleInstance的模式,则创建一个新的Activity时,会默认创建在一个新的Task任务栈中,并保证不再有其他Activity实例进入。这样说,大家可能难以理解,我们来演示一下。

现在我们将MainActivity的LaunchMode设为standard,SecondActivity设为singleInstance。

打开程序首先调出的是MainActivity,然后打开SecondActivity,接着又创建两个MainActivity,再启动SecondActivity,最后再创建一个MainActivity。这时我们按下Back键,应该销毁MainActivity调用SecondActivity,但是实际上是一直将所有MainActivity销毁后最后才是SecondActivity。

每次要调用SecondActivity其实都是从Task2中调用,只要Task2中存在SecondActivity就不会重新创建,而从调用MainActivity,其实是把Task1置在顶上,所有要先将Task1清完才会到Task2。

2、FrameWork层的类介绍

1、ActivityThread

ActivityThread作用大概就是用于控制与管理一个应用进程的主线程的操作,包括管理与处理activity manager发送过来的关于activities、广播以及其他的操作请求。

不了解ActivityThread(注意这个类是隐藏的,在api中无法看到,要看源码)的人看倒它的名字,肯定认为这是个管理Activity的线程,但其实并不是线程,在源码中可以看到ActivityThread并没有继承Thread,不过可以把它看作主线程,因为功能都是有它实现的。

ActivityThread是在主线程用到的一个类,它不是线程类只是在主线程的一个方法中运行。它在启动的时候首先会调用自己的main方法,这个main方法是它所需要的一些核心分析的代码的方法:

ActivityThread被启动后,首先会创建一个消息轮询对象(Looper.prepareMainLooper),然后会实例化一个自己的对象(ActivityThread thread = new ActivityThread()),用这个对象又去调用自己的attach()方法(thread.attach(false)),之后会调用它的Looper轮询对象。这个Looper轮询对象就是我们经常在Activity中用到消息队列,这个消息队列就是在ActivityThread的main()方法中创建的。

当ActivityThread创建完成这些方法之后,它就会通知AMS(Activity Manager Service),因为我们在启动一个应用进程之后,我们所有的Activity交互处理的逻辑都是由AMS统一管理。

接下来我们要来分析在用ActivityThread创建了应用的主线程之后与AMS交互的情况。大家可以自己去看看源码,我们来讲一下如何导入,否则像ActivityThread这样的隐藏的类我们是看不到的。首先我们要下载FrameWork的源码,这里有我的百度云盘链接FrameWork。查看源码的软件我也提供一个Source Insight,用Source Insight来查看源码的步骤大家可以看看这篇博客Source Insight 查看Android源码

在交互的过程中要先拿到IActivityManager(IActivityManager mgr = ActivityManagerNative.getDefault()),得到这个远程代理对象,我们就可以进行交互,交互的时候调用获得的IActivityManager对象的attachApplication()方法(mgr.attachApplication(mAppThread))。mAppThread是Binder对象的具体实例。

2、ApplicationThread

ApplicationThread继承ApplicationThreadNative,而ApplicationThreadNative是Binder的子类,所以这个类是要与远程端通信,这个远程端就是我们的AMS,所以这个ApplicationThread就是跟AMS通信的Binder的具体实现类,像暂停Activity这样的逻辑都是在这里确定的。它的初始化就是我们的ActivityThread里(ApplicationThread mAPPThread = new ApplicationThread())作为一个全局变量。

3、ActivityClientRecord

ActivityClientRecord是我们客户端的一个Activity描述的类,用作记录,是ActivityThread的内部类。

打开它的源码,我们可以看到ActivityClientRecord定义很多的变量,这些变量都是与Activity息息相关的,每个Activity创建的时候都会有ActivityClientRecord当记录。比如Activity的parent是什么,Configuration的配置是什么,权限等等。

4、ActivityRecord

ActivityRecord与ActivityClientRecord很相似,ActivityClientRecord是客户端存储Activity的记录,而ActivityRecord是AMS当中存储Activity的记录的类。两个类的结构是差不多的,就不多讲。

3、Activity生命周期分析

我们在我的上一篇博客Android四大组件–Activity详解(一)讲的生命周期只是讲解了各个方法的调用顺序,而它们是如何被回调的我们要作为一名优秀的Android开发人员也是应该知道的。

一个客户端所运行的进程当中唯一的主线程就是main线程,而main线程所执行的代码就是我们在上面介绍的ActivityThread,ActivityThread就有处理Activity生命周期的回调,具体的实现是通过AMS给我们跨进程通信进行回调的。

在了解Activity的生命周期如何回调,我们还要了解几个类。

1、Instrumentation

这个Instrumentation就是负责打开我们Activity各种生命周期方法,并且它也可以创建我们Application的对象,application是用来保存全局变量的,这个对象的创建都是由Instrumentation控制的。它还可以启动Activity,通常我们启动一个Activity都是通过startActivity()或者startActivityForResult(),我们如果通过源码跟踪,会发现最终会调用Instrumentation相关的方法。它帮助AMS更好的管理Activity。

2、ActivityManagerNative

在上面我们提到过,ActivityManagerNative是AMS一个远程代理端的对象,使用它可以与AMS进行远程通信。大家知道应用程序是在一个单独的进程中,AMS同样是在一个单独的进程中,它们两个要进行通信,就是用ActivityManagerNative实现底层操作。

3、H类

在ActivityThread类中有一个很重要的类,类名是H,这个H类它继承了Handler。H类的作用是对AMS发送过来的一些跨进程通信信息的处理。在H类的handleMessage()方法中我们能看到LAUNCH_ACTIVITY这么个case,顾名思义就是启动Activity,它就是通过各种case处理不同的逻辑。

4、onCreate()

我们在平时开发中打开程序,然后就能看见Activity的界面了,那么Activity的创建究竟是如何实现的呢。在上面提到的H类中有个handleLaunchActivity()方法,它会调用一个performLaunchActivity()方法,这个方法会创建Activity的对象,创建过程中有涉及到Activity生命周期的一些回调。Activity的创建是通过Java的反射机制。首先通过classloader加载相关Activity,Activity与普通类不同的就是有生命周期的处理,这些处理就调用了Activity的attach()方法,在之前会创建Application对象。attach()只要是将Activity与WindowManager进行关联,因为它需要控制我们整个窗口的界面显示。关联后就会对Activity生命周期的方法进行回调,调用Instrumentation的callActivityOnCreate()方法。

5、onResume

Activity的显示中间也有很多复杂的交互逻辑,它是通过WindowManager对象把我们的window设置到窗口当中。把View添加到窗口中用得是ViewRootmpl这个类。与onCreate()方法一样,onResume()方法相关控制在H类的handleResumeActivity()中实现,先拿到ActivityCilentRecord整个Activity的信息描述,它是从performResumeActivity()这个方法中获得,里面有对onResume()方法的回调。然后在调用getWindow()和getWindowManager()后,就会调用ViewManager的addView()方法将View添加到窗口当中,在方法里创建了ViewRootImpl对象,我们对每个View的操作都是通过这个类进行管理,比如非UI线程不能更新的判断。添加完后就会把View设置为可见状态makeVisible(),我们的onResume()就这么实现了。

6、onStop

前面介绍时是说onStop()方法是给Activity设置了一个不可见的状态。在H类中有handleStopActivity()方法,在用performStopActivity()方法回调了onStop()方法,接下来调用了updateVisibility(),在这个方法里将View设置为不可见。所以说是让Activity不可见,其实仍是让一个View不可见。

7、onDestroy

在H类的handleDestroyActivity()方法中,首先从WindowManager中获得了最外层的View,然后就将View给移除。在Activity被创建的时候会有一个Context对象,而在Activity被移除的时候也要把这个Context移除。最后就是调用ActivityManagerNative这个客户端代理对象向AMS发送消息可以移除当前的Activity,然后就可以被AMS在一定的时间内将其移除。但是在代码中我们会发现并没有将我们的Activity置为null,所以Activity还在内存中存在。

4、Activity、Window、WindowManager

我们Android平台只要是根据MVC模式设计的,在控制层就是我们Activity来做处理,关于Activity的介绍在前篇博客中已有介绍Android四大组件–Activity详解(一)

我们所添加的View其实就是添加到Window的对象中,在Android中,我们的一个Window对象就对应了一个窗口,控制我们界面的显示,但所有界面的管理都是WindowManager所做的,它会远程的WindowManagerService进行交互,相当于一个代理处理的对象。

结束语:本文仅用来学习记录,参考查阅

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值