Activity

1.生命周期

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

用图形来表示他们之间的关系


Activity_第2张图片

"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 所需的任务栈的名字为当前应用的包名。


3.启动模式

  • standard:
    标准启动,Activity每次都会 onCreate
  • singleTop:
    如果置于栈顶 onNewIntent(),如果栈中不存在这个Activity,onCreate会调用。反之则 onNewIntent();
  • singleTask:
    检测整个 Activity 栈是否有当前需要启动的 Activity,自带 clear 属性。特殊情况:其他程序以 singleTask 启动创建一个新的任务栈。 如果栈中不存在这个Activity,onCreate会调用。反之则 onNewIntent();
  • singleInstance:
    单实例模式,除了拥有singleTask的属性外,还加强了一点,就是这种模式的Activity只能单独位于一个任务栈中。

指定启动模式

  • 中指定。
  • 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.
一般这样封装比较好,如下:

  1. 在 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);
    }
}
  1. 在 B 中传递数据给 A。
setResult(RESULT_OK, getIntent().putExtra("paytype", result));
finish();
  1. 在 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;
    }
}

参考资料

  • Android面试一天一题(Day 20:程序员何苦为难程序员(下))

相关链接

  • 请戳我的博客,如何判断Activity是否在运行
  • 请戳我的博客,从源码分析Activity的启动过程

你可能感兴趣的:(Activity)