Activity生命周期图
官网的 Activity 的生命周期图:
在官方文档中给出了说明,不允许在 onPause() 方法中执行耗时操作,因为这会影响到新 Activity 的启动。
常见情况下Activity生命周期的回调
(A 与 B 表示不同的 Activity )
情况 | 回调 |
---|---|
第一次启动 | onCreate() -> onStart() -> onResume() |
从 A 跳转到 B | A_onPause() -> B_onCreate() -> B_onStart() -> B_onResume() -> A_onStop() |
从 B 再次回到 A | B_onPause() -> A_onRestart() -> A_onStart() -> A_onResume() -> B_onStop() |
用户按 home 键 | onPause() -> onStop() |
按 home 键后回到应用 | onRestart() -> onStart() -> onResume() |
用户按电源键屏保 | onPause() -> onStop() |
用户按电源键亮屏 | onRestart() -> onStart() -> onResume() |
用户按 back 键回退 | onPause() -> onStop() -> onDestroy() |
关于Activity生命周期常见问题
问题 | 回调 |
---|---|
由活动 A 启动活动 B时,活动 A 的 onPause() 与 活动 B 的 onResume() 哪一个先执行? | 活动 A 的 onPause() 先执行,活动 B 的 onResume() 方法后执行 |
标准 Dialog 是否会对生命周期产生影响 | 没有影响 |
全屏 Dialog 是否会对生命周期产生影响 | 没有影响 |
由活动 A 启动活动 B时,主题为 Dialog 的B Activity 是否会对生命周期产生影响 | 有影响, A.onPause -> B.onCrete -> B.onStart -> B.onResume |
Activity如果中途被回收了,再次启动是如何恢复原始数据的?
Activity类中提供了onSaveInstanceState()回调方法,这个方法可以保证活动在被回收之前一定会被调用,因此我们可以通过这个方法来解决活动被回收时临时数据得不到保存的问题。
以下面项目为例:
在MainActivity中添加如下代码就可以就可以将临时数据进行保存。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "save data";
outState.putString("data_key", tempData);
}
数据是已经保存下来的,那么我们该如何恢复呢?修改MainActivity中的onCreate()方法
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(savedInstanceState !=null){
String tempData=savedInstanceState.getString("data_key");
Log.d(TAG,tempData);
}
}
一些问题:
关于 onSaveInstanceState 与 onRestoreInstanceState 方法需要注意的一些问题:
-
onSaveInstanceState 方法的调用时机是在 onStop 之前,与 onPause 没有固定的时序关系。而 onRestoreInstanceState 方法则是在 onStart 之后调用。
-
正常情况下的活动销毁并不会调用这两个方法,只有当活动异常销毁并且有机会重现展示的时候才会进行调用,除了资源配置的改变外,activity 因内存不足被销毁也是通过这两个方法保存数据。
-
在 onRestoreInstanceState 和 onCreate 都可以进行数据恢复工作,但是根据官方文档建议采用在 onRestoreInstanceState 中去恢复。
-
在 onSaveInstanceState 和 onRestoreInstanceState 这两个方法中,系统会默认为我们进行一定的恢复工作,具体地讲,默认实现会为布局中的每个 View 调用相应的 onSaveInstanceState() 方法,让每个视图都能提供有关自身的应保存信息。Android 框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复付 UI 所做的任何可见更改。例如 EditText 中的文本信息、ListView 中的滚动位置等。也可以通过 android:saveEnabled 属性设置为 “false” 或通过调用 setSaveEnabled() 方法显式阻止布局内的视图保存其状态,通常不会将该属性停用,除非想要以不同方式恢复 Activity IU 的状态。
-
onSveInstanceState() 常见的触发场景有:横竖屏切换、按下电源键、按下菜单键、切换到别的 Activity 等;onRestoreInstanceState() 常见的触发场景有:横竖屏切换、切换语言等等。
Activity的四种启动模式
一、相关知识
1.一个应用程序通常会有多个Activity,这些Activity都有一个对应的action(如MainActivity的action),可通过action来启动对应Activity(隐式启动)。
<action android:name="android.intent.action.MAIN" />
2.一个应用程序可以说由一系列组件组成,这些组件以进程为载体,相互协作实现App功能。
3.任务栈(Task Stack)或者叫退回栈(Back Stack)介绍:
任务栈用来存放用户开启的Activity
在应用程序创建之初,系统会默认分配给其一个任务栈(默认一个),并存储根Activity
同一个Task Stack,只要不在栈顶,就是onStop状态
任务栈的id自增长型,是Integer类型
新创建Activity会被压入栈顶。点击back会将栈顶Activity弹出,并产生新的栈顶元素作为显示界面(onResume状态)
当Task最后一个Activity被销毁时,对应的应用程序被关闭,清除Task栈,但是还会保留应用程序进程,再次点击进入应用会创建新的Task栈。
4.Activity的affinity:
affinity是Activity内的一个属性(在ManiFest中对应属性为taskAffinity)。默认情况下,拥有相同affinity的Activity属于同一个Task中
Task也有affinity属性,它的affinity属性由根Activity(创建Task时第一个被压入栈的Activity)决定
在默认情况下,所有的Activity的affinity都从Application继承。也就是说Application同样有taskAffinity属性
Application默认的affinity属性为Manifest的包名。
二、Activity启动模式:
1.默认启动模式——standard
Activity的默认模式就是standard。在该模式下,启动的Activity会依照启动顺序被依次压入Task中:
2.栈顶复用模式——singleTop
在该模式下,如果栈顶Activity为我们要新建的Activity(目标Activity),那么就不会重复创建新的Activity。
3.栈内复用模式——singleTask
与singleTop模式相似,只不过singleTop模式是只是针对栈顶的元素,而singleTask模式下,如果task栈内存在目标Activity实例,将task内的对应Activity实例之上的所有Activity弹出栈, 将对应Activity置于栈顶,获得焦点。
4.全局唯一模式——singleInstance
在该模式下,我们会为目标Activity分配一个新的affinity,并创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点。新的Task有且只有这一个Activity实例。 如果已经创建过目标Activity实例,则不会创建新的Task,而是将以前创建过的Activity唤醒(对应Task设为Foreground状态)
三、动态设置启动模式
上述所有情况,在Manifest中通过launchMode属性设置,被称为静态设置,动态的设置Activity启动方式(如果同时有动态和静态设置,那么动态的优先级更高)。
动态设置是通过设置要启动的Activity的启动模式:
intent.setFlags(...);
几个常见的Flag:
1、NEW_TASK
Intent.FLAG_ACTIVITY_NEW_TASK
与singleInstance很相似:在给目标Activity设立此Flag后,会根据目标Activity的affinity进行匹配,如果已经存在与其affinity相同的task,则将目标Activity压入此Task。 反之没有的话,则新建一个task,新建的task的affinity值与目标Activity相同。然后将目标Activity压入此栈。
2、SINGLE_TOP
Intent.FLAG_ACTIVITY_SINGLE_TOP
与静态设置中的singleTop效果相同
3.CLEAR_TOP
Intent.FLAG_ACTIVITY_CLEAR_TOP
与singleTask相似当设置此Flag时,目标Activity会检查Task中是否存在此实例,如果没有则添加压入栈,如果有,就将位于Task中的对应Activity其上的所有Activity弹出栈,此时有以下两种情况:
如果同时设置Flag_ACTIVITY_SINGLE_TOP,则直接使用栈内的对应Activity,
没有设置,则将栈内的对应Activity销毁重新创建。
由FirstActivity启动SecondActivity最佳写法
在android的APP中Intent的跳转时最常用的方法之一。在这里我对Intent的跳转进行了整理,实现了比较好用的一种写法。
理由:传参数时直接调用方法就知道传什么参数了,有效防止漏传。
修改 SecondActivity 中的代码,如下所示:
public class SecondActivity extends BaseActivity {
public static void actionStart(Context context, String data1, String data2) {
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("param1", data1);
intent.putExtra("param2", data2);
context.startActivity(intent);
}
……
}
在FirstActivity调用即可启动SecondActivity
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SecondActivity.actionStart(FirstActivity.this, "data1", "data2");
}
});