Activity
1.生命周期
第一次启动:
onCreate->onStart->onResume
跳转其他页面:
onPause->onStop
回到页面:
onRestart->onStart->onResume
结束当前页面:
onPause->onStop->onDestroy
异常情况下的生命周期分析
onSaveInstanceState 与 onRestoreInstanceState(TextView 等都有这个方法)
对于 onSaveInstanceState 的调用说明:
Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key)
从这句话可以知道,当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行(按 home 旋转屏幕等等),除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
对于onRestoreInstanceState什么时候被调用
onRestoreInstanceState()被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行 此也说明上二者,大多数情况下不成对被使用。
- 我们可以通过 onRestoreInstanceState 和 onCreate 方法来判断Activity是否被重建了,
- 可以通过android:configChanges="orientation|screenSize"...来阻止Activity重新创建。
问题1:
当前页面是 Activity A ,如果用户打开一个新的 Activity B, 那么 B 的 onResume 和 A 的 onPause 那个先执行?
A->onPause
B->onCreate
B->onStart
B->onResume
A->onSaveInstanceState
A->onStop
2.任务栈
Task是为了完成某个工作的一组相关联的Activity的集合
为了方便大家更直观感受一下,可以使用adb命令查看一下当前运行的Task:
adb shell dumpsys activity activities
注意其中的几个关键字
Stack
TaskRecord
ActivityRecord
用图形来表示他们之间的关系
"Hist"代表Task中的ActivityRecord,可以理解成对应某个实际的Activity。
"Stack #0"表示mHomeStack(ActivityStack类),保存了Launcher相关的Activity的Task。
"Stack #1"表示mFocusStack(ActivityStack类),用于保存Launcher除外的其他应用的Activity组成的Task。
这两个Stack由ActivityStackSupervisor负责组织管理,在Android 4.4之前的版本是没有ActivityStackSupervisor这个类的,也没有"Stack #"的划分,AMS直接管理Task的列表。
TaskRecord{4226f148 #60 A=com.ryg.chapter_1 U=0 sz=5}
Run #5: ActivityRecord{41a7e988 u0 com.ryg.chapter_1/.MainActivity t60}
Run #4: ActivityRecord{41a68f40 u0 com.ryg.chapter_1/.MainActivity t60}
Run #3: ActivityRecord{418d32f8 u0 com.ryg.chapter_1/.MainActivity t60}
Run #2: ActivityRecord{4212a450 u0 com.ryg.chapter_1/.MainActivity t60}
Run #1: ActivityRecord{4226ee78 u0 com.ryg.chapter_1/.MainActivity t60}
其中 com.ryg.chapter_1 代表 taskAffinity 值,我们也可以为一个Activity指定任务栈,如下:
TaskAffinity 标识了一个 Activity 所需要的任务栈。默认情况下,所有 Activity 所需的任务栈的名字为当前应用的包名。
<activity
android:name="com.ryg.chapter_1.MainActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTask"
android:taskAffinity = "com.jack.org1"></activity>
3.启动模式
- standard:
标准启动,Activity每次都会 onCreate - singleTop:
如果置于栈顶 onNewIntent(),如果栈中不存在这个Activity,onCreate会调用。反之则 onNewIntent(); - singleTask:
检测整个 Activity 栈是否有当前需要启动的 Activity,自带 clear 属性。特殊情况:其他程序以 singleTask 启动创建一个新的任务栈。 如果栈中不存在这个Activity,onCreate会调用。反之则 onNewIntent(); - singleInstance:
单实例模式,除了拥有singleTask的属性外,还加强了一点,就是这种模式的Activity只能单独位于一个任务栈中。
指定启动模式
- <manifest> 中指定。
- Intent 中为 Activity 设置标记位,优先级高些。
Intent intent = new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Flags 常见的标记位
1.FLAG_ACTIVITY_NEW_TASK
当Intent对象包含FLAG_ACTIVITY_NEW_TASK标记时,系统在查代时(和设置了singleTask启动模式一样都是)按Activity的taskAffinity属性进行匹配,如果找到一个Task的taskAffinity与之相同,就将目标Activity压入此Task栈中,如果找不到则创建一个新的Task。
2.FLAG_ACTIVITY_SINGLE_TOP
3.FLAG_ACTIVITY_CLEAR_TOP
4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
不希望用户通过历史列表回到我们的 Activity 的时候,这个标记位比较有用。
4.startActivityForResult
注意点:要保证 要启动的 activity 的启动模式是 standard, A 启动 B.
一般这样封装比较好,如下:
- 在 B 中,设置一个方法,供 A 去启动 B
public static void startChoosePayActivity(Activity activity, int guaranteeFee, int requestCose) {
Intent intent = new Intent(activity, ChoosePayActivity.class);
intent.putExtra("guaranteeFee", guaranteeFee);
if (requestCose == -1) {
activity.startActivity(intent);
} else {
activity.startActivityForResult(intent, requestCose);
}
}
- 在 B 中传递数据给 A。
setResult(RESULT_OK, getIntent().putExtra("paytype", result));
finish();
- 在 A 的 onActivityResult 取出值
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) {
return;
}
switch (requestCode) {
case IntentContent.PAYTYPE_SELECT_REQUEST:
int nPaytype = data.getIntExtra("paytype", -1);
E_PAY_TYPE e_pay_type = E_PAY_TYPE.valueOf(nPaytype);
switch (e_pay_type) {
case PAY_ALIPAY:
LogUtils.i(TAG, "支付宝支付");
break;
case PAY_WECHAT:
LogUtils.i(TAG, "微信支付");
break;
case PAY_WALLET:
LogUtils.i(TAG, "钱包支付");
}
break;
}
}
参考资料
相关链接
- 请戳我的博客,如何判断Activity是否在运行
- 请戳我的博客,从源码分析Activity的启动过程