生命周期
生命周期流程图典型情况下生命周期(右边的流程)
-
单击打开应用
打开应用 -
点击Back键,退出应用
GIF.gif
结果输出日志为下图
2018-11-23_224758.png -
切换出去,然后再返回,只要切换的速度够快,就可以实现,在将activity放入后台(onStop)之前,返回。其实可以从动图中看见,这个activity几乎可以一直可见
GIF.gif
2018-11-23_225801.png
但是如果稍微慢一点,执行同样的操作,系统就会将其放入后台(onStop)
慢一点后输出的日志
启动新的activity顺序:调用
instrumentation
,然后instrumentation向AMS
发送开启新activity的请求,AMS内部有一个activitystack
,存有activity状态的栈,其会先onPause
栈顶的activity,然后开始新的activity
异常情况下生命周期(右边的流程)
补充内容
- onSaveInstanceState:保存数据
- 用户主动点击Back键,即
主动销毁activity时
,不执行onSaveInstanceState方法
其他异常销毁
activity情况,是需要执行onSaveInstanceState方法的,如屏幕从竖屏切换到横屏
- 这个activity有可能被销毁的情况下,也会调用,如
按home
键返回桌面、启动一个新的Activity等(如果内存不够用,就有可能销毁之前的activity)
- onRestoreInstanceState:恢复数据
当第一个activity由于内存不足被销毁了,执行了onSaveInstanceState
方法后,由于不是用户主动销毁的,会调用onRestoreInstanceState
-
资源配置改变,导致Activity被杀死 并重新创建(横屏切换到竖屏)
可以配置资源配置:android:configChanges="orientation"
:当屏幕切换时,activity不重新创建。但是当资源配置改变时,需要执行onConfigurationChanged
方法 -
资源内存不足导致优先级低的应用被杀死
正在和用户交互的activity >>> 可见但非前台(比如弹窗(非ProgressDialog)后,activity可见,但被放入后台了)>>> 不可见、被放入后台(onStop)
启动模式
taskAffinity:任务相关性,标识一个Activity所需要的栈的名字,默认所有任务栈名字为应用包名,只对
栈内复用模式
和单实例模式
有用,其他两个都是默认只识别启用者(执行startActivity)的堆栈
。
1.standard:标准模式
每启动一个Activity,就会创建一个实例
谁启动了Activity(标准模式),被启动的Activity
就会进入启动者的堆栈中
但是,如果是启动Activity这个活动的类的类型为Context(如:getApplicationContext获取),就会报错android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
,这个报错提示你,需要提供一个flag:FLAG_ACTIVITY_NEW_TASK,表示创建新的任务栈来运行这个activity,这个时候启动的其实是sigleTask模式启动的
context启用activity
获取全局Context(还需要在Mainifest中填写Application:name=".getGlobalContext "):
public class getGlobalContext extends Application {
private static Context context;
@Override
public void onCreate() {
context = getApplicationContext();
super.onCreate();
}
public static Context getContext(){
return context;
}
}
启用:
Context = getGlobalContext.getContext();
context.startActivity(new Intent("secondactivity"));
2. singleTop:栈顶复用模式
如果要启用的Activity实例已经位于栈顶
,那么这个Activity不会再创建了
,同时其onNewIntent 方法会被回调,同时可以获取请求的数据
当然,如果没在栈顶
,在栈内其他地方还是可以被创建的,并且这个activity实例只会进入启动者的堆栈中
<activity android:name=".secondActivity"
//给这个活动的taskAffinity属性赋值:即定义一个新的相关联的任务栈名称
android:taskAffinity="com.app.typicallifecycle.secondTaskStack"
android:launchMode="singleTop">
<intent-filter>
<action android:name="secondactivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
当从MainActivity启动secondActivity时,adb shell dumpsys activity查看堆栈信息,可以看见在同一任务栈下
Running activities (most recent first):
TaskRecord{4a91ab14 #21 A=com.app.typicallifecycle U=0 sz=2}
Run #1: ActivityRecord{4a989564 u0 com.app.typicallifecycle/.secondActivity t21}
Run #0: ActivityRecord{4a963ca4 u0 com.app.typicallifecycle/.MainActivity t21}
3. singleTask:栈内复用模式(单例模式)
Activity B请求启动后,会先找想要的栈
(先看taskAffinity的值,如果没有这个值,再看启动者),如果没有
就会创建一个新的栈,并放入。如果有
找到想要的栈,先看栈内是否有其实例,如果有将栈内该实例调到栈顶,并回调onNewIntent 。如果没有则压入栈
4. singleInstance:单实例模式
加强版的栈内复用模式。当一个新的Activity请求启动时,创建一个新的栈并压入该Activity,并且这个栈中有且只有这个模式下的Activity。如果同一Activity请求启动,那么只有等这个特殊任务栈被销毁才行
如果没有给需要启动的activity(单实例模式),设置taskAffinity属性,在不同任务栈下
Running activities (most recent first):
TaskRecord{4a8c3cbc #20 A=com.app.typicallifecycle U=0 sz=1}
Run #1: ActivityRecord{4a8e6b34 u0 com.app.typicallifecycle/.secondActivity t20}
TaskRecord{4a92525c #19 A=com.app.typicallifecycle U=0 sz=1}
Run #0: ActivityRecord{4a8bdd08 u0 com.app.typicallifecycle/.MainActivity t19}
上面四种启动模式,介绍的是单一任务栈,下面开始介绍多个栈下的调用关系
当未开启任何应用时,存在一个栈Stack #0
,可以通过adb shell dumpsys activity
查看,可以这个栈看为系统栈
,这个栈只存有少数的activity,例如:主界面、活动列表(存有最近打开的应用,即使销毁了,也可以通过此来重新创建)
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Stack #0:
打开任意应用,都会压入另一个栈Stack #1
,里面有很多任务栈(Task id )
Stack #1:
Task id #64
TaskRecord{4a913c8c #64 A=com.app.typicallifecycle U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.app.typicall
ifecycle/.MainActivity }
Hist #0: ActivityRecord{4a8bd970 u0 com.app.typicallifecycle/.MainActivity t64}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.app.typi
callifecycle/.MainActivity bnds=[431,618][572,848] }
ProcessRecord{4a8e6b88 9229:com.app.typicallifecycle/u0a30}
Task id #63
TaskRecord{4a8e281c #63 A=com.tencent.mm U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tencent.mm/.
ui.LauncherUI (has extras) }
Hist #0: ActivityRecord{4a8f1728 u0 com.tencent.mm/.ui.LauncherUI t63}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tencent.
mm/.ui.LauncherUI bnds=[290,618][431,848] (has extras) }
ProcessRecord{4a8d12fc 9076:com.tencent.mm/u0a28}
Running activities (most recent first):
TaskRecord{4a913c8c #64 A=com.app.typicallifecycle U=0 sz=1}
Run #1: ActivityRecord{4a8bd970 u0 com.app.typicallifecycle/.MainActivity t64}
TaskRecord{4a8e281c #63 A=com.tencent.mm U=0 sz=1}
Run #0: ActivityRecord{4a8f1728 u0 com.tencent.mm/.ui.LauncherUI t63}
-
即使将activityA加入
Stack #0
栈中,如果从activityA中开启一个acitivityB,并且acitivityB的任务栈不在Stack #0
中,那么acitivityB所在的任务栈会加入Stack #1
-
实例1:
绘图1.png任务栈
之间的混用
- 开启应用
typicallifecycle
,创建了第一个任务栈(com.app.typicallifecycle)
,并将第一个activity压入栈中,当开启第二个activity时,由于下面的代码配置,会将这个secondActivity
放入已经开启的微信的栈中,如上面流程图所示,然后按返回键会返回到微信的界面
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".secondActivity">
android:taskAffinity="com.tencent.mm"
android:launchMode="singleTask">
<intent-filter>
<action android:name="secondactivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
任务栈之间的混用
也可以同样的方法用在
系统栈Stack #0
,这样会直接返回到主界面
网友评论