最近在看任玉刚的“Android开发艺术探索”,结合自己的最近面试情况和对一些问题的理解,来试着回答一些比较经典的问题吧。话不多说,试着去记录自己的想法吧:
只是典型的分析,不涉及到异常的启动分析哦。
A. onCreate()
表示Activity正在被创建,它为Activity生命周期的第一个方法。在这个方法中我们可以做一个初始化工作,比如setContentView()和初始化一些数据的方法。
B.onRestart()
表示Activity正在重新被创建。正常的情况下,当Activity从不可见状态变为可见状态时,onRestart()将会被调用。Activity被压入栈底然后退到栈顶,onRestart()将会被调用。
C.onStart()
表示Activity正在被启动,此时Activity界面时可见的,但是无法获取焦点,也就是无法和用户进行交互。此时可以理解为可见的Activity,但是非前台Activity。
D.onResume()
表示Activity已经可见,且已经获取焦点,可以与用户进行交互了。
E.onPause()
表示Activity正在停止,此时Activity依然可见,但是已经失去焦点。正常情况下,紧接着onStop()就会被调用。在特殊情况下,此时快速返回Activity,那么onResume会被调用。可以做一些数据存储,停止动画等不太耗时的操作。因此只有新的Activity要显示时,必须等到旧的Activity执行完onPause和onStop。
F. onStop()
表示Activity即将停止,此时Activity已经不可见了,可以做一些稍微重量级的回收工作,同样不能太耗时。
G. onDestroy()
表示Activity即将被销毁,这是最后一个生命周期可回调的方法。在这里我们可以做一些回收工作和最终的资源释放。
对于整个生命周期而言,onCreate和onDestroy是配对的,分别标识着Activity的创建与销毁,都只可能被调用一次;从Activity的可见性而言,onStart和onStop是配对的,随着用户的操作,这两个方法可能被调用很多次;对于Activity是否处于前台而言[换句话说是否对用户存在交互]onResume和onPause是配对的,随着用户的操作和设备的屏幕的点亮和熄灭,这两种方法也可能被调用多次。
既然存在配对,且onStart和onResume,onPause和onStop看起来差不多,在看起来接口有些重复的情况,我们是否可以只保留其中一对呢?答案是不能的,原因是这两对回调分别表示不同的意义,onStart和onStop是从Activity是否可见的这个角度来进行回调的,而onResume和onPause是从Activity是否位于前台的这个角度来回调的,除了这种区别,在实际使用中没有其他明显的区别。
启动模式有四种,分别为standard,singleTop,singleTask,singleInstance四种模式。
standard模式
标准的启动模式,也是Android系统中默认的启动方式,每次启动一个Activity都会重新创建一个新的Activity,不考虑任务栈中是否存在这个实例。每一个新创建的Activity实例都会将生命周期方法统一走一遍:onCreate –> onCreate –> onResume。这是一种典型的多实例实现方式,一个任务栈中可以有多个实例共存,每一个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。如果一个Activity A启动按standard模式启动了Activity B,那么B就会进入A所在的任务栈中。
singleTop模式
栈顶复用模式,如果你将要启动的Activity的实例正好位于任务栈的栈顶,那么此时Activity将不会被重建,只是会调用Activity的onNewIntent方法,通过此方法我们可以读取一些参数信息。按照所说的,Activity的onCreate,onStart由于Activity没有被重建,因此不会被调用。那么另一种情况是,如果将要的启动的Activity在对应的任务栈中没有该Activity的实例,或者存在Activity的实例,但是该实例不在任务栈顶,此时该Activity还是会像standard模式那样重建新的实例。举个例子,现在任务栈中存在A->B->C三个activity实例,假如要启动一个C的实例,由于C的启动模式时singleTop的,那么此时任务栈还是A->B->C;如果此时要启动B的实例,虽然任务栈中还存在B的实例,但其实例不在栈顶,那么B还是会创建,最终任务栈为A->B->C->B.
singleTask模式
任务栈内服务模式。这是一种单实例模式。在这种模式下,只要Activity在一个栈中存在,不管是否在栈顶、栈中还是栈底,Activity都不会被重建,只会调用其onNewIntent方法。具体点,当一个具有singleTask模式的Activity请求启动之后,就像Activity A,系统回首先查找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例把A放到栈中。如果存在A所需的任务栈,这时候要看A是否在任务栈中存在实例,如果实例存在,那么系统就会把A调到栈顶并同时调用它的onNewIntent方法,如果实例不存在,就创建A的实例并把A压入栈中。
对于这个是否需要的任务栈,取决于将要启动的Activity的Context,如果这个Context是个Application,那么将会创建一个新的任务栈,如果是一个Activity,那么A将进入这个Activity的栈顶位置。举几个例子吧:
singleInstance
功能和说singleTask类似,也是一种单实例模式,但它是一种加强型的singleTask模式,它除了singleTask的所有特性之外,还有另外一点就是此种模式下的Activity只能单独位于一个任务栈中,换句话说,比如Activity A是singleInstance模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。
那么对于singleTask和singleInstance,singleTask在JVM中可以因为不同的任务栈可以创建多个Activity的实例,但是singleInstance是位于一个单独唯一的任务栈,理论上Activity模式为singleInstance时,在JVM中最多只能存在一个实例。
什么是任务栈呢?这需要从一个参数说起:TaskAffinify,可以翻译为任务相关性。这个参数标识了一个activity所需要的任务栈的名字,默认情况下所有的Activity所需要的任务栈的名字都是应用的包名。当然我们可以为每个activity都单独制定TaskAffinity属性,属性值必须不能和包名相同,否则就相当于未指定。TaskAffinity主要和SingleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。另外任务栈还分为前台任务栈和后台任务栈,后台任务栈中的activity位于暂停状态,可以通过切换将后台任务栈再次调到前台。
Intent.FLAG_ACTIVITY_NEW_TASK
标记位的作用是为Activity指定”singleTask”启动模式,其效果和在XML中指定该启动模式相同.
Intent.FLAG_ACTIVITY_SINGLE_TOP
这个标记为的作用是Activity指定”singleTop”的启动模式,其效果和在XML中指定该启动模式相同。
Intent.FLAG_ACTIVITY_CLEAR_TOP
具有次标记位的Activity,当它启动时,在用一个任务栈中所有位于它上面的Activity都要出栈,该模式一般需要和Intent.FLAG_ACTIVITY_NEW_TASK相配合使用,在这种情况下,被启动的Activity的实例如果已经存在,那么系统就会调用它的onNewIntent方法;如果被启动的activity采用standard模式,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。
startActivity(new Intent(this,MainActivity.class).
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_CLEAR_TOP));
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有这个标记的Activity不会出现在历史Activity列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。它等同于XML中指定Activity的属性android:excludeFromRecents=”true”;
好了,今天的总结就到这了。