Activity知识细节之Activity的启动过程

        Activity是Android的四大组件之一,也是我们开发的App使用频率最高的核心组件。由于是组件,由Framework来管理,我们没办法像普通的数据类型一样,构造一个对象,调用其中的函数来实现我们的业务逻辑。通常是创建Activity的子类,在里面完成我们的代码,然后向Framework发送一个Intent,来把我们的Activity启动。

        针对Activity的使用方式我们知道,需要我们的App和Framewok协同工作才能维护好一个Activity。其中Framework的管理,个人的理解包括两个方面:一方面需要站在Task的角度对所有的Activity进行管理,从而在用户点击back,home按键时,Activity的跳转符合用户的预期;另一方面是Framework需要知道App中Activity的状态,以此来确定App进程的优先级。当我们向Framework通过Intent发送了一个启动Activity的指令了之后,Framework也会回调App进程的函数,从而保证Activity的创建和以onCreate()为首的生命周期函数的调用发生在我们App进程的主线程中。在这个交互的过程中,就会涉及到Android的两大利器:Handler和Binder,分别来实现线程和进程间的通信。也就是说,为了维护好Activity,需要App进程和系统进程频繁交互,具体负责交互的是ActivityThread和Framework 的ActivityManageService。

一:ActivityThread

       首先来看ActivityThread,对于ActivityThread,通俗的理解为是我们App的主线程。更具体的解释是:一方面负责对主线程的管理,主要是四大组件的启动,另一方面可以理解为接受来自AMS的请求。先来看一下其中的main函数,里面的主要代码为:

ActivityThread$main()

       主要做了两件事,一是给当前主线程开启Loop循环,另一个就是创建ActivityThread的对象,并调用attach函数。而attach函数也主要做了两件事,一件是将ActivityThread的ApplicationThread类型的变量传给AMS:

Activity$attach-1

         另一个就是,给ViewRootImpl添加了一个ComponentCallback对象:

ActivityThread$attach-2

         至于ApplicationThread和ViewRootImpl的细节,我们后面会讲,这里只是先简单的铺垫一下。接下来步入正题,当我们想启动Activity的时候,就通过startActivity(Intent intent)向系统发送指令,而它内部又会调用startActivityForResult,startActivity()就是一个requestCode小于0的startActivityForResult.它里面的实现为:

startActivityForResult()

       通过源码,我们知道,它内部调用了Instrumentation的execStartActivity函数。Instrumentation可以理解为一个监控类,监控我们的App和系统的交互,类似于AOP,拦截器,做一些统一的逻辑。而Instrumentation的execStartActivity的内部实现为:

execStartActivity()

       通过源码,我们发现它内部实际调用了ActivityManager的startActivity函数。启动一个Activity,需要向系统发送指令,而这个地方就用到了进程间通信,也就是AIDL,Binder这些知识点。AIDL和IPC相关的介绍,可以看作者另一篇关于Service的文章,这里我们来着重分析一下AMS。

         AMS,Activity Manager Service,也就是系统给我们提供的Activity管理的服务。所谓的服务,本质上也就是一个Aidl的接口,系统的服务进程里有相应的实现类对象,然后将接口对象通过Binder的方式传递给我们,而这个接口类型就是IActivityManager。要想实现App和系统进程的IPC,首先有IActivityManager,并且需要实现IInterface:

IActivityManager

        通过查看源码,我们确认IActivityManager继承自IInterface,那现在服务进程给我们提供的接口定义好了。接下来还需要对应的类似于Stub的类,就是ActivityManagerNative:

ActivityManagerNative

       那现在我们App作为客户端,所需要的接口和Stub都有了。下一步就是通过类似于bindService的方式,来得到IBinder,然后通过ActivityManagerNative.asInterface将它转化为IActivityManager,从而调用AMS。但这个地方没有使用bindService,得到客户端所需要的IActivityManager的方式是调用ActivityManager的getDefault函数:

ActivityManager$getDefault()

          而gDefault是一个单例,它的定义为:

gDefault

       那现在我们发现,IActivityManager对应的IBinder是通过调用ServiceManager的getService查询到的。对于ServiceManager,从名字上就很好理解,是系统用来对它对外提供的各种服务来管理的类,包括查询啊,注册啊等等操作。看到这里,很容易想到ServiceManager就有点类似于Binder里面的连接池,想要哪种服务直接通过ServiceManager来查询就好。而ServiceManager的函数调用,本身也是跨进程的。ServiceManager的源码可以看这里,同时笔者又参考了https://blog.csdn.net/u012545728/article/details/80622187这篇文章,这里给出关键部分:

ServiceManager

      基于连接池的角度,我们也很容易想到,ServiceManager肯定有一个对应的IInterface类型的接口,是IServiceManager。同时,也会有对应的Stub,是ServiceManageNative。那下一步就要拿到IServiceManager对应的IBinder,这个是通过BinderInternal得到的,个人理解为应该是Binder驱动的概念。拿到了IBinder,然后通过ServiceManagerNative.asInterface转化为对应的接口。这样层层调用,我们的App就可以拿到IActivityManager在App端的代理,然后跨进程调用系统服务。

       对于AMS,还有一个问题就是,相关的ActivityManagerNative和IActivityManager都是隐藏的,对我们不可见的,如果我们想使用这个服务,只能通过Context.getSystemService的方式来获取,那这个又是怎么获取的呢。 这个函数的实现,context最终会交给ContextImpl来做:

ContextImpl$getSystemService

        而ContextImpl又交给了SystemServiceRegistry,这个类从名字上看是系统服务注册器,有点类似于ServiceManager,但它俩不是一个东西,这个后面会涉及到。我们接着看SystemServiceRegistry:

SystemServiceRegistry$getSystemService

          从代码上看,它是从一个Map里,根据服务名字,拿到了一个ServiceFetcher:

ServiceFetcher

        而ServiceFetcher可以理解为服务获取器,而刚才的Map是在SystemServiceRegistry的静态代码块里就完成了注册:

static code

       那看到这里,我们就知道,通过getSystemService得到的AMS对象是一个ActivityManager,我们以其中随便一个函数来看,它又是怎么工作的:

ActivityManager$getAppTasks()

      原来,它内部也是依赖于ActivityManagerNative.getDefault来工作的,这一段流程有点乱,我们慢慢的捋一捋。首先,系统给我们提供的AMS就是IActivityManager,然后这个接口在App本地的代理是单例的,通过ActivityManager的getDefault函数得到。至于单例的原因,也很好理解。就拿我们正常开发的App来说,当你想使用某个Service的某个接口的时候,bindService调用一次和调用多次是没有区别的,因为返回的IBinder都是同一个,系统会做缓存的。所以当我们的App严重依赖于某项服务,这项服务使用频率很高,就完全可以将这个接口对象设置成单例的,缓存起来,等想用的时候直接拿过来用就可以了。就像ActivityManagerNative一样,可以用一个单独的类来负责连接,并缓存,下次使用的时候直接使用,不用再连接了。但IActivityManager,ActivityManagerNative和ServiceManager这些东西我们是没法访问的,所以系统就提供了一个替代的ActivityManager。ActivityManager一方面类似于Messenger一样,就是一个壳子,内部封装了IActivityManager相关的东西,屏蔽了细节。另一方面也限制了我们对于AMS的使用,只能使用ActivityManager对外暴露的函数。对于ActivityManager,我们也没办法直接构造它的对象,因为它的构造函数我们也没权限访问,所以只能通过Context的getSystemService来使用,同时也让返回的ActivityManager和Context有了一定的依赖。

         那现在就有了服务名称,Context和服务对象三者的对应关系。服务名称和服务是一一对应的,一个Context可以有多种类型的服务,但每一种服务在同一个Context内部是单例的,而且还需要懒加载,因为并不是所有的Context都需要用到系统服务,提前加载没有意义。但每种服务对象在同一个App中可以有多个,因为一个App会有很多种不同类型的Context的不同对象。对于这些对应关系,ContextImpl交给了SystemServiceRegistry来负责。SystemServiceRegistry提供的getSystemService函数,是根据服务名称,查询某个Context对象上缓存的该项服务。很容易想到的解决方案是在SystemServiceRegistry里面维护一个数据结构,建立这三者的对应关系。但这么做相当于在SystemServiceRegistry有了Context的引用,这样做是非常不合适的,有可能会造成内存泄漏。虽然可以使用WeakReference来解决,但终究不是最优解。所以Android采取了类似于ThreadLocal的思路,将这个数据结构定义在Context内部,由Context自己来维护它自己对应的各项服务对象,而Context使用的是一个数组来完成的:

mServiceCache

         而这个数组又是通过SystemServiceRegistry来完成的:

createServiceCache()

       那这里,我们可以得出两个结论:一是Context并没有采用Map这样的数据结构,来建立服务名和服务对象之间的对应关系,采用的是数组,每个服务对象对应数组中固定的索引。而且在App所有类型的Context之前,SystemServiceRegistry的sServiceCacheSize的数值,肯定已经等于了系统可以对外提供的服务数量。

       基于这些结论,我们在来看一下SystemServiceRegistry的静态代码块,这些代码会随着这个类的加载而加载。在这段代码里,它会将系统可以提供的所有可用的服务的ServiceFetcher都注册到内部的Map集合里。这里之所以使用ServiceFetcher,个人认为主要是为了实现懒加载,在真正有需要的时候,才创建对应的类似于ActivityManager对象们。这个地方使用的是CacheServiceFetcher:

CachedServiceFetcher

      它的逻辑是每个CachedServiceFetcher对应的是一种类型的服务,当构造这个CachedServiceFetcher对象的时候,也指定了对应的服务在Context数组中的索引,并且会把sServiceCachedSize+1,这样等所有的服务都注册完了,sServiceCachedSize就和服务的数量保持一致了。然后我们通过ServiceFetcher的getService获取对应服务的时候,直接拿对应的index获取就好,也不会有角标越界的问题。个人觉得这个地方的处理逻辑还是挺有意思的,很值得我们思考和借鉴,有机会的话可以在项目中使用。那现在,我们就很清楚的了解到了AMS相关的几个重要的细节,回过头来,继续看Activity的启动。

       当完成了向FrameWork发送指令来启动某个Activity,而Framework完成了自己的工作后,还会回调App的代码,因为Activity对象的创建和onCreate等生命周期的调用是发生在App进程的主线程中的,那这个时候就又会进程间调用,而App提供给Framework的回调接口则是ApplicationThread,并且已经在调用ActivityManagerNative.getDefault().startActivity的时候传递给了Framework。ApplicationThread是ActivityThread的内部类,它继承自ApplicationThreadNative,并实现了IApplicationThread接口,而IApplicationThread是app提供给Framework的,Framework通过调用其中的函数来通知App做相应的工作,

IApplicationThread

        当Framework完成了自己的工作后,就会调用IApplicationThread的scheduleLaunchActivity函数来通知App来做Activity对象的创建和生命周期函数调用等工作。至于系统回调IApplicationThread的具体细节,由于笔者暂时还没仔细查看源码,这里就先略过了。在《Android开发艺术探索里》有提到这一部分,涉及到了ActivityStack,有兴趣的可以看一下。ApplicationThread里面的scheduleLaunchActivity逻辑为:

scheduleLaunchActivity()

       scheduleLaunchActivity里面先把被启动Activity的关键信息封装在ActivityClientRecord对象里,然后就发送了一个消息。因为这个函数是被Framework通过IPC调用的,那么这个函数在App的Binder线程池里执行,而Activity的创建和生命周期的调用,需要在主线程执行,所以这个地方通过Handler来实现了线程的切换。自定义的Handler对LAUNCH_ACTIVITY消息的处理为:

LAUNCH_ACTIVITY

        内部调用了handleLaunchActivity函数,这个函数里面的代码东西比较多,我们一点点分析。首先,它调用了performLaunchActivity()函数:

handleLaunchActivity()

        而performLaunchActivity里面的逻辑主要包括:

performLaunchActivity

       首先,根据Intent来确定目标Activity的组件名字。这个Intent可能是显示的,也可能是隐式。当为隐式的时候,则会通过resolveActivity来确定Activity的组件名称,这也是为什么我们自定的Activity要想可以通过隐式的Intent的启动,清单文件里就必须声明“android.intent.category.DEFAULT”的原因。确认了目标Activity之后,接下来就通过Instrumentation的newActivity函数来创建对象,而这个函数的构造Activity对象的方式也比较简单,就是利用反射:

Instrumentation$newActivity

       至此,完成了目标Activity对象的构造。当构建了Activity对象之后,在调用onCreate等生命周期之前,更重要的一件事是调用Activity的 attach函数。这个函数有两个作用,一方面是完成几个重要变量的赋值,比如mApplication,mIntent等等,而另一方面设置Context。对于Context这里先简单总结一下,一般都理解为上下文。上下文就是当前代码运行的环境,可以通过Context来获取应用的资源或者访问系统的类,比如Activity,所以startActivity定义在了Context中。和Context非常相似的两个类是ContextWrapper,ContextImpl。ContextWrapper可以理解为Context的一个代理,它将全部的操作交给了它依赖的真实的Context来做,也就是base字段,有点像装饰着模式或者代理模式,而Activity就是一个ContextWrapper。而Context本身是一个抽象类型,所以Activity真实依赖的base的类型是ContextImpl。

       根据上面的分析,在调用Activity的attach函数之前,首先需要准备好Application对象:

performLaunchActivity-2

        通过代码我们知道,Application对象是通过LoadedApk的makeApplication来得到的:

makeApplication

        在makeApplication函数中,首先通过ContextImpl的createAppContext来构造了一个ContextImpl对象。因为Application对象也是一个ContextWrapper ,所以它也需要一个ContextImpl对象赋值给base。而Application的创建则是通过Instrumentation的newApplication函数来完成:

newApplication

     它里面的逻辑也比较简单,先通过反射构造Application对象,然后调用attach函数来设置base Context。对于App来说,我们直到Application的创建发生在任何一个Activity之前。那么在刚才的performLaunchActivity中,通过LoadedAPK的makeApplication来得到Application对象的时候,LoadedApk的mApplication肯定已经有值,然后直接返回了。那么它的mApplication字段是什么时候赋值呢。这个地方笔者没有深入的研究,但是猜测应该是在bindApplication中。

       IApplicationThread里面定义了bindApplication函数:

bindApplication

       顾名思义,就是用来绑定Application对象的。最终会调用handleBindApplication函数,这个函数逻辑也是比较复杂,我们只关注其中的关键部分。首先是调用getPackageInfoNoCheck生成了LoadedAPK对象:

handleBindApplication

     而getPackageInfoNoCheck内部又调用了getPackageInfo函数:

getPackageInfo

       getPackageInfo一方面构造了LoadedAPK对象,另一方面会把这个对象缓存起来。因为getPackageInfo和getPackageInfoNoCheck会被多次调用,来给ActivityThread的LoadedAPK类型的packageInfo字段赋值。有了LoadedAPK对象之后,handleBindApplication后面会调用LoadedAPK的makeApplication来生成Application对象,这样就会在App的组件之前生成了Application对象,后续的Activity这些组件直接拿来用就可以了。

       处理完了Application之后,又如法炮制的通过ContextImpl的createActivityContext来给Activity准备base Context,最后才调用Activity的attach函数:

Activity$attach

        在attach函数里面,我们清楚的看到了完成了base Context,mApplication,mIntent的赋值,这也是我们后面可以在生命周期函数里通过getIntent来得到传递的Intent对象的原因。还有几个字段mInstrumentation,mMainThread以及可以通过mMainThread获得的ApplicationThread,这些字段都是startActivity函数中使用到的关键字段。这里有个特殊的字段mToken,可以理解为Framework的AMS给Activity贴的标签,等后面App告诉Framework启动的是哪个Activity以及同步Activity状态的时候,回传这个字段就好了,不需要回传Activity对象。而它的数据类型是IBinder,笔者debug的时候发现实际上是一个BinderProxy,这个地方就是利用到了IBinder在跨进程中的唯一性。在调用完了attach函数之后,接下来就是调用相应的生命周期函数,首先就是onCreate:

call onCreate

      这里有个需要注意的字段是Activity的mCalled字段,因为Android限制有的生命周期函数是必须调用super的,如果没调用就会抛异常,而这个地方就是通过mCalled来判断的。super的实现会把它设置为true,如果没调用super,就会是false:

判断mCalled

      这样就完成了onCreate的调用,而我们在onCreate里面的业务代码也完成了调用。在调用完onCreate之后,下一步就是调用onStart。不过在调用onStart之前,需要判断,当前的Activity有没有被finish。Activity内部有个boolean类型的字段mFinished,当Activity调用finish()或者用户点击back按键的时候,mFinished就会被设置为true。一个常用的场景,可以用这个字段在onPause()中来判断当前的activity是短暂的pause还是彻底的finish了:

call onStart()

        在Activity没有被finish的前提下,就会通过performStart()来调用onStar()函数,而onStart中有这么一行代码:

Activity$onStart()

        会调用相应Application的dispatchActivityStarted()函数。我们知道一个App在单进程的情况下会有一个Application,单这个app可能会有很多个Activity。如果我们想对所有的Activity进行统一的监控,比如添加广告显示,就需要一个单独的监听Activity生命周期的接口,而Application内部定义了一个这样的接口:ActivityLifecycleCallbacks:

ActivityLifecycleCallbacks

        如果我们有这个需求,只需要调用Application的registerActivityLifecycleCallbacks函数来将我们自定义的ActivityLifecycleCallbacks注册即可:

registerActivityLifecycleCallbacks

        就像刚才的onstart函数一样,所有的生命周期周期函数,都会通过Application向外分发,这样,我们自定义的ActivityLifecycleCallbacks对象就会接收到回调,有点类似观察者模式。调用完了onStart之后,接下来就会根据有没有保存的状态state来决定调不调用onRestoreInstanceState()函数。这个函数的目的是让我们可以在Activity意外被杀死的情况下,通过这个函数来恢复状态。之后就会调用onPostCreate函数,这个使用不常见,就不解释了。最后,会将这个Activity对应的ActivityRecord保存当ActivityThread内部的一个ArrayMap中:

mActivities

       这里解释一下这个mActivites的作用,会涉及到另一个类ComponentCallbaks:

ComponentCallbacks

        这是一个接口,它里面定义的是Android应用中所有的组件,包括Application在内,都通用的函数:onConfigurationChanged和onLowMemory。每个组件都实现了这个接口,这些函数也可以理解为生命周期函数,只不过所有的组件都通用,就单独定义了一个接口。只不过现在不直接使用这个接口了,用的是它的子类ComponentCallbacks2。ComponentCallbacks2不一样的地方在于,对于内存管理这块,有了更精细的控制。当其中一个事件发生时,比如配置改变,系统也是用类似的手段来回调ActivityThread的函数,这个时候就需要把所有的ComponentCallbacks2收集起来,依次调用其中的函数,这就包括了所有的Activity,Application和Service。所以才需要有mActivities这个数据结构,存储存在的所有的Activity。具体的可以见collectComponentCallbacks函数的实现:

collectComponentCallbacks

       而collectComponentCallbacks会在handleTrimMemory,handleLowMemory和handleConfigurationChanged函数中用到。这是函数也是被Framework回调的,来处理相应的事件。

      至此,performLaunchActivity()函数的细节我们就分析完了。它里面主要就是完成了Activity对象的创建,以及onCreate,onStart等生命周期的调用。让我们继续回到handleLaunchActivity()函数中:

       我们知道,onStart之后,接下来就该是onResume了,而onResume的调用被放在了handleResumeActivity()里面:

handleResumeActivity-1

     handleResumeActivity里面做的事情比较多,首先调用的是performResumeActivity()函数:

performResumeActivity

       而performResumeActivity()里面做的事情比较简单,就是通过Activity的performResume函数来调用onResume函数:

performResume

        首先调用的是performRestart()函数,因为Activity的onResume被调用有两种情况,一种是Activity从创建到正常显示,而另外一种就是Activity从不可见到可见,这个时候就有可能需要调用onRestart。performRestart的实现为:

performRestart

       首先判断mStopped,这个boolean值可以理解为当前Activity的状态,为true的时候代表Activity不可见,这个时候就会依次调用onRestart和onStart。处理完了start相关的逻辑后,就开始调用onResume了,而这也就是perfromResumeActivity的逻辑,继续回到handleResumeActivity函数中:

handlerResumeActivity-2

        在调用完onResume之后,handlerResumeActivity先做的是将Activity的DecorView添加到Window系统中。这个地方涉及到了View的显示流程,会用单独章节来分析,这个地方简单的提一下。只有添加到Window系统中,我们的Activity才可以被看到。那这个时候就想到了老生常谈的一个问题,Activity的onStart和onResume有什么区别。目前从代码分析来看,没区别,只是调用顺序先后的问题,而且等onResume函数执行完毕了之后,Activity的视图才可以被看到,所以感觉本质上onStart和onResume没啥区别。

        在通过WindowManager添加完Activity的视图之后,这个时候Activity进入了reumed的状态,也就是用户可见,而这个状态是需要告知Framework的,因为Framework需要清楚的知道App的Activity的状态,来判断App的优先级,所以handlerResumeActivity中最后会调用ActivityManager的函数来通知Framework:

        并且,Framework感兴趣的只是Activity的状态,所以并不是所有的生命周期函数的调用都需要通知Framework,只有相应状态的函数被调用的时候才会通知Framework。至此,从Activity对象创建到显示给用户涉及到的onCreate,onStart,onResume三个函数就分析完了,剩下的onPause,onStop,onDestroy和刚才的三个大同小异,所以这里就简单的分析一下。

        正如前面所说,要想维护好一个Activity,需要App和Framework协同工作。对于Activity来说,主要关注其两方面:状态和生命周期函数的调用,其中Framwork需要关注状态,App需要关注生命周期函数的调用。当用户的某个行为导致了Activity状态发生改变的时候,ActivityThread就会通过IActivityManager的函数向Framework发送指令,Framework收到指令,完成相应的工作,就会通知App执行相应的生命周期函数。那接下来对于onPause函数来说,当Activity失去焦点了以后,Framework会回调ApplicationThread的schedulePauseActivity来通知ActivityThread,而ActivityThread会通过发消息的形式来调用handlePauseActivity:

handlePauseActivity-1

        首先,会涉及到两个不常见的生命周期函数onUserInteraction,onUserLeaveHint。当是由于用户的行为,让当前的Activity退居后台,比如按下home按键的时候,就会一起调用这两个函数。由于平时使用的不多,这个地方有个印象就可以。接下来就是调用performPauseActivity:

performPauseActivity

         performPauseActivity首先判断Activity的mFinished和saveState,在Activity没有被销毁并且saveState==true的情况下会调用Activity的onSaveInstance函数。而这个saveState的赋值比较简单:

isPreHoneycomb

       是通过版本号赋值的,也就是说如果APP的目标版本号在3.0之前,调用onPause之前会调用onSaveInstance函数。而onSaveInstance函数我们知道,是在意外的情况下,让我们保存Activity状态用的。所以这个地方,笔者猜测可能是版本兼容性问题,可能就是在3.0之前,调用onPause之前就会调用onSaveInstance。这个地方暂时没有验证,如有歧义,欢迎指正。调用完onSaveInstance之后,就是通过Instrumentation调用Activity的onPause函数了。调用完pause之后,就会把paused字段设置成true。在performPauseActivity最后,还有这么一段代码:

onActivityPauseListener

        这个OnActivityPausedListener接口的意思是:当你对某个Activity的paused状态感兴趣的时候,可以注册。这样当Activity的onPause被调用的时候,onActivityPausedListener的onPaused(Activity activity)函数也会被调用。ActivityThread有一个专门存储的字段mOnPausedListeners:

mOnPausedListeners

而相应的注册的函数也定义在了ActivityThread中:

register&unRegister

       只不过ActivityThread本身对我们来说是隐藏的,所以这些东西应该是给Framework别的地方准备的,只不过笔者也没找到具体的使用。当某个Activity的onPause被调用了之后,ActivityThread就会将这个Activity和相应的OnActivityPausedListeners集合从mPausedListeners中删除,然后依次调用OnActivityPausedListener集合中元素的onPause函数。

        至此,performPauseActivity函数的逻辑也就完成了。在调用完了performPauseActivity函数之后,handlePauseActivity就会通知Framework,当前的Activity处于paused状态了:

通知Framework

        分析完了onPause,下一个就是onStop。当Activity进入了stoped状态,也就是不可见的时候,这个函数就会被调用。首先还是Framework通过IApplicationThread的scheduleStopActivity()函数来通知ActivityThread,而ActivityThread继续通过发消息,然后在主线程调用handleStopActivity():

handleStopActivity-1

handleStopActivity的处理大同小异,还是先调用performStopActivityInner函数:

performStopActivityInner

       这里面有歧义的是onSaveInstance的调用。通过代码来看,onStop被调用之前,onSaveInstance一定会被调用的,因为saveState直接被设置成了true。而且在Nexus 6p测试,结果也确实如此,也就是说,即便Activity不是意外的被关闭,onSaveInstance也有被调用的可能。这个结果让人比较费解,因为以前我们接收到的理论都是,只有在Activity意外被关闭的时候,onsaveInstance才会被调用。但是从代码上看,调用onstop的时候,onsaveInstance一定会被调用,这就有冲突了。这个地方笔者暂时还没细想,也没有拿其他的机型来测试,后续在完善吧。

       接下来就会调用Activity的onStop函数。而onStop调用完了之后,paused,stopped这些字段也就都变成true了。并且,当onStop()函数执行完毕了之后,还应该把当前Activity的stop状态通知Framework,就像前面的pause,resume一样。只不过stop状态并不是马上通知Framework的,而是被封装在了StopInfo类里,这个类是一个Runnable:

StopInfo

        在StopInfo的run函数里调用了IActivityManager的activityStopped()函数,而StopInfo是在handleStopActivity()函数的最后,通过Handler来调用的:

handleStopActivity()

       这么做的目的,源码给的解释是因为开发者有可能会在onStop里面做一些资源释放的操作,通过Handler来调用StopInfo,就可以确保是在这些操作完全完成了之后,才通知Framework进行的状态变更。

       在分析完了onStop之后,那还有最后一个onDestroy()。这个函数意味着Activity的结束,要被销毁了。这里我们只分析Activity正常结束的情况,当用户点击back按键或者调用Activity的finish()的时候,就意味着这个Activity要开始被销毁了。用户点击back按键,调用的是onBackPressed(),而这个函数内部也会调用finish(),所以我们来看finish():

finish

        finish里面首先准备了可能需要回传给上个Activity的resultCode和Intent,然后通过ActivityManager的finishActivity向Framework发送结束这个Activity的指令。待返回后,会将mFinished设置为true。当mFinished==true的时候就意味着当前的Activity的finish()函数被调用了,正在结束的过程中,但这个时候onDestroy可能还没有被调用。它的一个使用场景是在onPause中来判断Activity只是失去焦点了还是被结束了。在Framework接受到我们的指令后,完成它自己的工作后,就会通过IApplicationThread的scheduleDestoryActivity来通知ActivityThread,之后就会调用handleDestroyActivity:

handleDestroyActivity-1

       handleDestroyActivity内部又是老生常谈的先调用performDestroyActivity:

performDestroyActivity

         而performDestroyActivity先是根据状态,来决定要不要调用onPause,onStop。然后就会调用onDestroy,最后会把这个Activity从mActivities这个Map集合中删除:

performDestroyActivity-2

        在调用onDestroy的时候会把Activity中的mDestroyed设置为true。mDestroyed一旦设置为true,就意味着这个Activity死亡了,完全没有存在的必要了。在调用完performDestroyActivity之后,handleDestroyActivity就会将Activity的视图从Window系统中删除:

删除视图

        删除完了视图,而Activity内部还有一个mBase字段,指向它依赖的ContextImpl对象,这个对象也会被释放:

释放ContextImpl

        在完成这些工作之后,接回通知Framework,我们这个Activity被销毁完成了,Framework也会随之进行状态的更新:

通知Framework

        以上,就是对Activity以onCreate为首的六个声明周期函数的调用过程的分析。但在Activity中,除了刚才的6个,还有两个也是经常用的函数,onNewIntent和onActivityResult。这两个函数的调用时机就不分析了,大家都很清楚,简单说一下细节。onNewIntent最终是通过performNewIntents来调用的:

performNewIntents

      里面唯一需要注意的是onPause,onNewIntent被调用,也代表了当前Activity被启动了,只不过没有创建新对象,而是拿已经存在的Activity来复用。这个时候onNewIntent相当于替代了onCreate,成为了Activity的入口。如果Activity此时paused为false,也就是正在于用户交互,那么就会先调用onPause。另一个是onActivityResult:

handleSendResult

        这里面也会有可能调用onPause,而且触发条件和onNewIntent一样。这个地方对应的业务场景是什么,笔者自己一时也没想到,以后遇到了再补充吧。

         到这里,Activity启动过程中涉及到的知识细节就分析完了。个人觉得,对于这些流程的了解,一方面可以让我们了解一些细节方面的东西,比如ContextImpl,ActivityLifecycleCallBack,ActivityThread和Instrumentation等等。另一方面是,可以让我们可以揭开系统的面纱,了解它内部的工作原理,以后开发的时候会心中有数。并且我们会发现,其实Android系统也没什么,也是Java代码,并不神秘,它的工作流程其实和我们的App并没有本质上的区别。

参考:《Android开发艺术探索》-任玉刚

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271