迷茫,是青春最真实的状态;但奋斗,才是青春的主基调;努力是打败焦虑的绝好方法!
安卓四大组件除了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被杀死并重新创建。
资源配置发生改变,比如屏幕的朝向(横竖屏),Activity会被销毁并且重新创建。
由于在异常情况下终止的,系统调用onSaveInstanceState来保存当前Activity的状态和数据,并将其封装为Bundle对象,在后面调用onRestoreInstanceState方法时作为参数传入,这个方法在onStop之前,并且只有在Activity异常终止的情况下才会被调用。
重新创建后,系统在onCreate新建Activity之后,在onStart之后调用onRestoreInstanceState来恢复数据。这个方法也只有在异常终止恢复数据时才会被调用,不然不会调用这个方法,而是正常创建新的Activity。 - 系统内存不足导致低优先级的Activity被杀死。
Activity优先级:- 前台Activity——正在和用户交互的Activity,优先级最高。
- 可见但是非前台Activity——例如弹出一个对话框,使Activity位于后台,无法和用户直接交互,优先级较高。
- 后台Activity——已经被暂停的Activity,如执行了onStop的,优先级最低。
当内存不够时,按照上述优先级进行销毁,在后续通过onSaveInstanceState和onRestoreInstanceState方法来恢复使用。
想要不重新创建Activity也是有方法的,在系统资源配置中设置configChanges的属性即可。
启动模式
如何指定Activity的启动模式?
- 在AndroidMenifest中使用launchMode属性即可。
android:launchMode="singleTask"
- 通过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复用。
- 如果在一个任务栈中已存在待启动的Activity并且其位于栈顶,那么它不会被重新创建一个新的实例,即上面生命周期的onCreate和onStart不会被调用,而是调用onNewIntent方法(这个方法现在我也不了解),这个方法是用来取出当前请求的信息的。
- 如果这个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的启动过程中的方法调用过程
- Activity的startActivity
- startActivityForResult
- Instrumentation.execStartActivity
- ActivityManagerNative.getDefault().startActivity
- AMS.startActivity
- startActivityAsUser
- ActivityStackSupervisor.startActivityMayWait
- startActivityLocked
- startstartActivityUncheckedLocked
- ActivityStack.resumeTopActivitiesLocked
- ActivityStack.resumeTopActivityInnerLocked
- startSpecificActivityLocked
- realStartActivityLocked
- app.thread.scheduleLaunchActivity
- ApplicationThead.scheduleLaunchActivity
- handleLaunchActivity
- 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方法。