Intent中的四个重要属性——Action、Data、Category、Extras
以上是对intent的介绍,接下来会再介绍一下task,也就是如何启动,以什么样的规则启动和退出。以下均指launchFlag,标记均以FLAG_ACTIVITY_开头,介绍时会忽略,请注意一下;启动时会依次判断如下标识
1、NO_USER_ACTION:含义无用户交互;基本不用,主要防止一段时间后执行onUserLeaving方法;接下来如果立即启动,就把r.delay.Resume设为true
2、PREVIOUS_IS_TOP:含义上个intent是否位于栈顶,基本不用;然后为activity赋予权限加入缓存;此时区别于launchMode和launchFlag,前者指activity自己声明的启动方式,后者是明显启动者想让activity如何启动,能过intent设置,但两者有相通性
3、NEW_TASK、SINGLE_TASK、SINGLE_INSTANCE:使用这三者均不建议使用startActivityForResut,而只限于使用startActivity即r.resultTo=0,不需要回传数据的情况下;第1个是会新起一个task,即两个task之间最好不进行数据回传;2和3的相同在于,如果已经存在这样的task和component以及其他相同数据如intent,则均跳到相应栈中,不存在则声明一个新的task;不同点在于:2的task里可以包含多个activity,而3仅能包含一个;可能跟每个task内存大小有关,不同功用的activity可以申请不同的task使用,这一点也可以看上面“Android基本之Activity LaunchMode详解”
4、CLEAR_TOP、REORDER_TO_FRONT:前者如自己存在,则清除该栈上面的其他activity;后者仅把自己放在最上面;举例A1->A2->A3,前者启动A2则变成A1->A2,后者启动A2则变成A1->A3->A2
5、NO_HISTORY:不要保存自己,设置A3,则A1->A2->A3->A4,执行完还是A1->A2,皮之不存,毛将焉附。
一般情况下,以上如果调整栈的顺序,那么是可以执行的;如A、B、C三个栈,分别有2个activity,如果从C切换到B,那么是这样的A1->A2->B1->B2->C1->C2,调整后A1->A2->C1->C2->B1->B2。
系统还提供另外一种办法来设置activity的启动方式,那就是
1、android:clearTaskOnLaunch=true/false:是否清除task里的其他activity
2、android:finishOnTaskLaunch:是否关闭task中已有的此activity
3、android:allowTaskReparent:是否将自己带入启动的task中
4、android:alwaysRetainTaskState:是否由系统维护activity状态;一般应用在根activity,每次可以打开最后打开的页面
最近讲的几个东西之间的关系,画了一张图,如下所示

正式启动工作(主要流程均为ActivityThread执行-在attach时初始化)
一、暂停当前activity
1、判断该activity是否存在;然后执行onUserLeaving方法,避免此activity再与物理按键交互,如后退键
2、调用performPauseActivity(告知暂停而非超时等情况,将prev指向自己),先onSaveInstanceState,再执行onPause
·3、报告AMS暂停完毕,通过IPC调用AMS的completePauseActivity方法
二、调用resumeTopActivity方法:
1、如果mHistory有记录且直接启动,否则执行startHomeActivityLocked方法启动主界面程序;
2、系统处于睡眠状态或当前activity未被暂停,则停止;
3、从mStoppingActivities和mWarningVisibleActivities里移除目标对象;
4、将被停止的activity设置为不可见状态,通知activty或task切换
5、判断目录进程是否存在并且activityThread存活,否则执行startSpecificActivityLocked方法;如果进程不存在,则调用
Process类启动新进程,设置pid加入ProcessRecord,启动完之后再通知Ams启动目标Activity,至于启动Process的过程跟调用
暂停或启用activity的过程无异,仅仅参数发生变化而已,以及变量不同和意义不同。当然我们再讲一点,启动进程毕
竟是个重要流程,提取odex文件,前面几篇文章有过介绍,指已经优化过的dex文件,通过Service、Provider和
Broadcast加入引用,创建完成。
6、最终调用performLaunchActivity,执行attach,执行setTheme,几个on方法,拿到DecorView加入Wms,设
置可见。
接下来咱们讲讲停止工作:一般情况下是长时间不使用,或者应用内存紧张,或者启动时设置no_history才会执行,执行过程
而应用与上面生命周期无异,也就是设置不可见,加个mStoppingActivities,异步通知Ams停止,最后调用onStop方法等等,
关闭activity也同样如此;至于关闭的优先级前面似乎没讲,接下来会着重介绍一下。
Android系统如何管理自己内存的?同样可以预习一下,原理协同,再做补充。
一般情况下优化级分为-16到15级,而android默认仅使用0-15级,越小优先级越高,当前可见activity最高为0。
为什么会产生这个优化级,主要android采用的是关闭而不退出,退出而不清理的原则,主要为了二次加载更加快速;
其次是上面停止activity的原因。而这个规则由Ams加权得出,有这样几个变量:是否展示在当前页或是持久化
activity、相应的配合组件、剩余内存量、HOME进程、活跃activity数量和组件等,就像JVM的内存管理规则一样,
详见:Java高级之虚拟机垃圾回收机制
由于Ams无法预知内存的变动(OOM除外),因而采用这套机制:最先是空进程(无activity进程),其次是
activity,再次是前台的配合组件,如Service、Receiver、Provider,最后才是前台activity;而这些操作由OOM Killer
进程直接管理,关于activity回收需要满足以下几种情况:
1、finish操作或crash或anr,通过updateOomAdjLocked方法让其指定优先级,动态调整
2、如果运行的activity超过20个,必须是已经stop的、不可见的、非常驻进程
因而不合理的手机架构也会造成系统的崩溃。PS:持久化对象的在ProcessRecord的persistent变量是否为true
LocalActivityManager存在于Activity内部,用来装载和管理activity以及各种状态,维持一个最低的内存消耗;核
心在于它使用UI线程的activityThread来装载指定的 activity;有同学可能会问task越少或者histroyRecord越小,内存
会占用越小吗?这个问题跟手机里装一个app和装n个app重量是否增加是一样的道理,但是越过限制以后(task允许)
内存占用确实会变大,直到出现OOM。
以下是按键方面的内容(锁屏下,基本均不操作)
1、后退键:Activity里监听到onBackPressed方法;一般执行的是finish动作,执行performDestroyActivity方法
2、Home键:Acitivty的onKey方法无法截取它,属于设计原因;Wms中使用PhoneWindowManager类中的
interceptKeyTi截取消息,发现是它,再执行launchHomeFromHotKey;2.0之后添加另一个Home键执行
startDockOrHome方法来监听硬件。
与普通的启动区别在于,能启动特殊的intent,方法在ContextImpl里。而长按震动、关闭所有窗口、会弹出LRT-
lasted recent task,可以调用Ams的getRecentTask来取出,通过弹出的窗体的点击事件,进入相应的应用。
总结一下:
进程启动:1、内核创建进程数据结构,指出其地址总线
2、装载函数,读取代码,拿到数据总线
3、将程序指针指向目标地址入口
虚拟机启动:首次是从Zygote进程fork出来一个子进程,用来加载资源,然后启动SystemSever,用来监
控手机按键和触摸事件,以及管理Ams、Pms、Wms等,最终根据配置文件的HomeActivity,启动它。
Activity启动,然后触发init.rc文件执行main函数,启动一个ActivityThread
这就是所谓的UI线程,由Looper声明一个MessageQueue,接着创建Activity对象,初始化ViewRoot和token,用来分
发消息和接收转换为本地消息,为后面执行Activity的生命周期,创建PhoneWindow,执行attach方法,初始化内部组
件,根据Wms返回的消息,适时的执行生命周期,执行setContentView创建DecorView(View内部也有ViewRoot来设置View的各种属性),由Wms加入到窗口中,设置Visiable,加载结束。
注:每个应用仅有一个ActivityThread来异步处理内部事务,如果出错则App Crash;具体应用启动后,会创建ApplicationThread和ActivityThread,分别用来处理应用事务和Activity事务,并且创建MessageQueue,不停的轮循;AMS通过判断加载某个Activity和资源的加载情况,将消息从手机端通过Binder发给当前应用的ViewRoot对象,通过handler把消息放入消息队列,轮循出来的消息处理,即推动Activity的生命周期执行。
问题1:在应用运行过程中Window有多个吗?是的,每个Activity都会创建Window(见1)。
问题2:在应用运行过程中WindowManager有多个吗?Activity的WindowManager通过系统的WindowManager创建(见2、3、4)
Activity类
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
1、 mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } mUiThread = Thread.currentThread(); mMainThread = aThread; mInstrumentation = instr; mToken = token; mIdent = ident; mApplication = application; mIntent = intent; mReferrer = referrer; mComponent = intent.getComponent(); mActivityInfo = info; mTitle = title; mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; if (voiceInteractor != null) { if (lastNonConfigurationInstances != null) { mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor; } else { mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this, Looper.myLooper()); } }
2、mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); }
3、mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config; }Window类: