[2018_android_2]Activity之lifecycle_TBD25html
感谢各位大牛分享精彩内容,帮助了我快速学习。
Thank Ujava
Visible
, Invisible
, Background
, and Foreground
? [TBD]
Fragment
生命周期结合Activity生命周期? Activity
的启动过程源码比较复杂,涉及到Instrumentation
, ActivityThread
and ActivityManagerSercice(AMS)
。 [TBD] Window
、Dialog
、Toast
和Activity
的关系 android
正常状况(又称典型状况)下的生命周期,指的是用户参时,Activity所经历的生命周期改变。
正常状况下的生命周期 ,主要关注生命周期函数的调用顺序,在每一个生命周期要作什么?不能作什么?git
[TBD] Visible
, Invisible
, Background
, and Foreground
?
Visible:表示activity可见状态,即activity已经显示出来了。
Invisible:表示activity不可见状态,即activity没有显示出来了。
Background:activity位于后台,即没法与用户交互。
Foreground :activity位于前台,便可以与用户交互。github
Activity lifecycle
Figure 1. A simplified illustration of the activity lifecycle. 网络
https://developer.android.google.cn/guide/components/activities/activity-lifecycle.htmlapp
// A -> B D/A: onPause D/B: onCreate: D/B: onStart D/B: onResume D/A: onSaveInstanceState D/A: onStop // A <- B D/B: onPause: D/A: onRestart: D/A: onStart D/A: onResume D/B: onStop: D/B: onDestroy:
[A] 继续执行,直到执行完毕,或者当app进程被杀死,未执行完的线程被强制中止。 ide
执行onDestroy()后,未执行完的线程,继续执行。函数
// Test on Nenux 5X, Android 8.0, API 26 // A -> B,而后A <- B后, // 执行onDestroy()后,未执行完的线程还会继续执行: D/AActivity: onStart D/AActivity: onResume D/BActivity: run: i=9 D/BActivity: onStop: D/BActivity: onDestroy: I/zygote64: Do partial code cache collection, code=23KB, data=28KB I/zygote64: After code cache collection, code=23KB, data=28KB I/zygote64: Increasing code cache capacity to 128KB D/BActivity: run: i=10 D/BActivity: run: i=11 D/BActivity: run: i=12
当用户从Recent list close app,未执行完的线程被强制中止,由于整个app进程被杀死,分配的全部资源被OS回收。工具
用户从Recent list close app D/BActivity: run: i=590 D/BActivity: run: i=591 D/BActivity: run: i=592 // 用户从Recent list close app,未执行完的线程中止运行 D/AActivity: onPause D/AActivity: onSaveInstanceState D/AActivity: onStop D/BActivity: run: i=593
[TBD]
Fragment
生命周期结合Activity生命周期?
// Open app, A is mainActivity D/A: onCreate: D/A: onStart D/A: onResume // A -> B D/A: onPause D/B: onCreate: D/B: onStart D/B: onResume D/A: onStop // A <- B D/B: onPause: D/A: onRestart: D/A: onStart D/A: onResume D/B: onStop: D/B: onDestroy: // Press back , A -> Homescreen, exit A and APP D/A: onPause D/A: onStop D/A: onDestroy
对于单个Activity,such as A:
与启动 normal Activity相比,启动Float Activity或Translucent时,A 仅仅执行onPause,不执行onStop.
Back to A时,A 不执行OnStart,仅仅执行onResume.
Note: 没有特殊说明,要跳转的Activity是普通Activity,不是Float/Translucent activity。
// Open app, A is mainActivity D/A: onCreate: D/A: onStart D/A: onResume // A -> TranslucentB D/A: onPause D/TranslucentB: onCreate: D/TranslucentB: onStart D/TranslucentB: onResume // A <- TranslucentB D/TranslucentB: onPause: D/A: onResume D/TranslucentB: onStop: D/TranslucentB: onDestroy: // Press back , A -> Homescreen, exit A and APP D/A: onPause D/A: onStop D/A: onDestroy
// Open app, A is mainActivity D/A: onCreate: D/A: onStart D/A: onResume // A -> FloatB D/A: onPause D/FloatB: onCreate: D/FloatB: onStart D/FloatB: onResume // A <- FloatB D/FloatB: onPause: D/A: onResume D/FloatB: onStop: D/FloatB: onDestroy: // Press back , A -> Homescreen, exit A and APP D/A: onPause D/A: onStop D/A: onDestroy
跟跳转到本身 app的其余Activity是同样的。
// Open app, A is MainActivity D/A: onCreate: D/A: onStart D/A: onResume // Screen OFF ,由于跳转到其余activity(Locks Screen app的Activity) D/A: onPause D/A: onSaveInstanceState D/A: onStop // Screen ON D/A: onRestart: D/A: onStart D/A: onResume
这两个配对的回调分别表明不一样的意义。
onStart和onStop是从Activity是否可见角度来回调。
onResume和onPause是从Activity是否位于前台角度来回调。
除了这种区别,在实际使用当中没有其余明显区别。
A:
// A -> B D/A: onPause D/B: onCreate: D/B: onStart D/B: onResume D/A: onStop
[TBD] Activity的启动过程源码比较复杂,涉及到Instrumentation, ActivityThread and ActivityManagerSercice(AMS)。
如何简单理解?
启动Activity的请求会由Instrumentation来处理, 而后Instrumentation经过Binder 向AMS发送请求,AMS内部维护一个ActivityStack并负责栈内的Activity的状态同步,AMS经过ActivityThread去同步Activity的状态而完成生命周期方法的调用。
图Instrumentation经过Binder 向AMS发送请求:
[TBD1]源码中的红色错误代码是怎么回事
图ActivityStack.java - resumeTopActivityInnerLocked()
ActivityStackSupervisor.java - realStartActivityLocked()
IApplicationThread thread ,实现是ActivityThread中的ApplicationThread。
这段代码其实是调用ApplicationThread中的scheduleLaunchActivity(),scheduleLaunchActivity()最终完成新Activity的onCreate,onStart,onResume。
图ActivityStackSupervisor.java - realStartActivityLocked()
图 源码ApplicationThread.java # scheduleLaunchActivity()
A -> B ,A 中onStop模拟耗时操做:开启一个Thread,打印从1~1000的整数,每次打印一个整数,Thread.sleep 1 second.
A 在onPause中模拟耗时操做也是同样的。由于是在一个子线程里面执行,对生命周期函数的执行没有影响。
@Override protected void onStop() { Log.d(TAG, "onStop"); // 不管super.onStop() 先后调用testIfInOnStopCanDoHeavyWork,log都是同样的。 testIfInOnStopCanDoHeavyWork(); super.onStop(); // testIfInOnStopCanDoHeavyWork(); } private void testIfInOnStopCanDoHeavyWork() { if (null != counter) { return; } counter = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { Log.d(TAG, "run: i=" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); counter.start(); }
//Open app, A is Main activity. D/A: onCreate D/A: onStart D/A: onResume // A -> B D/A: onPause D/B: onCreate: D/B: onStart D/B: onResume D/A: onStop D/A: run: i=0 D/A: run: i=1 D/A: run: i=2 D/A: run: i=3 D/A: run: i=4 D/A: run: i=5 D/A: run: i=6 D/A: run: i=7 D/A: run: i=8 D/A: run: i=9 D/A: run: i=10 D/A: run: i=11 D/A: run: i=12 D/A: run: i=13 D/A: run: i=14 D/A: run: i=15 D/A: run: i=16 D/A: run: i=17 D/A: run: i=18
<video id="video" controls="" preload="none" poster="http://media.w3.org/2010/05/sintel/poster.png"> <p>Check if onStop can do heavy work. </p> <source id="mp4" src="https://yingvickycao.github.io/img/android/app_component/activity/life_cycle/chec_if_can_do_heavy_work_in_onStop_4_app.mp4" type="video/mp4"> <source id="mp4" src="https://yingvickycao.github.io/img/android/app_component/activity/life_cycle/chec_if_can_do_heavy_work_in_onStop_4_logcat.mp4" type="video/mp4"> </video>
Check if onStop can do heavy work.
Check if onStop can do heavy work.
异常状况下的生命周期,指的是Activity被系统回收或者因为当前设备的Configuration改变时,致使Activity被销毁所经历的生命周期改变。
TBD[2], 了解系统的资源加载机制
把图片放入drawable目录后,经过Resource去获取图片。为了兼容不一样设备,可能须要在其余目录防止不一样的图片:drawable-mdpi,drawable-hdpi,drawable-land等。 layout也是相似:layout,layout-large,layout-land等。
当app启动时,系统会根据当前设备的状况去加载合适的Resource资源,例如横屏和竖屏分别拿landscape和portrait状态下的资源:layout、图片.... 。
当旋转屏幕,因为系统配置发生了改变,在默认状况下,Activity 会被销毁并从新建立。 也能够阻止系统从新建立Activity。
打开 auto-ratate模式
<!-- activity没有设置跟资源配置相关的属性 --> <activity android:name=".app_component.activity.lifecycle.A"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter>
layout文件夹包含 landscape(横屏)和portrait(竖屏)状态的layout。
layout-landscape仅仅包含landscape状态的layout。
layout-portrait仅仅包含portrait状态的layout。
//Open app, A is Main activity. D/A: onCreate: D/A: onStart D/A: onResume // 旋转屏幕 D/A: onPause D/A: onSaveInstanceState D/A: onStop D/A: onDestroy D/A: onCreate: D/A: [onCreate]restore extra_test:test D/A: onStart D/A: [onRestoreInstanceState]restore extra_test:test D/A: onResume
系统只在Activity异常终止的时候才会调用onSaveInstanceState与onRestoreInstanceState来储存和恢复数据,其余状况不会触发这个过程。可是按Home键或者启动新Activity仍然会单独触发onSaveInstanceState的调用:由于用户可能再也不回来了,要作现场保护。
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.d(TAG, "onSaveInstanceState"); outState.putString(INSTANCE_STATE_KEY, "test"); }
二者的区别:
若是是正常启动, onCreate的参数savedInstanceState = null,必须判断是否为null。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate: "); setContentView(R.layout.activity_app_component_activity_lifecycle_a_layout); if (savedInstanceState != null) { String test = savedInstanceState.getString(INSTANCE_STATE_KEY); Log.d(TAG, "[onCreate]restore extra_test:" + test); } } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); String test = savedInstanceState.getString(INSTANCE_STATE_KEY); Log.d(TAG, "[onRestoreInstanceState]restore extra_test:" + test); }
onSaveInstanceState 保存数据,onRestoreInstanceState 恢复数据。
缘由: OS只有在Activity异常终止时才会调用onSaveInstanceState 和 onRestoreInstanceState。
在onSaveInstanceState和onRestoreInstanceState中,系统自动会作View的相关状态的保存和恢复工做,好比 文本框的数据、ListView滚动位置等。
具体特定View能恢复什么数据,要View的onSaveInstanceState和onRestoreInstanceState源码。
VIew.java实现了onSaveInstanceState和onRestoreInstanceState函数,它的派生类会重写这两个函数实现保存和恢复特定数据。
采用委托思想,上层委托下层、父容器委托子元素去处理一个事情。
委托思想在Android 有不少应用,View的绘图过程、事件分发等采用相似的思想。
Step1: Activity 被意外终止,Activity会调用onSaveInstanceState保存数据,而后Activity会委托Window去保存数据。
Step2: Window 委托它上面的顶级容器去保存数据。顶级容器是一个ViewGroup,通常来讲多是DecorView。
Step3: 顶级容器再去一一通知它的子元素来保存数据。
经过委托,完成整个数据保存工程。
[TBD] 检查API有没有更新,并对每个属性进行测试 。国内android官网没有搜到 configChanges结果
经过为Activity设置configChanges属性,当屏幕旋转时Activity不销毁并从新建立。
A 添加 android:configChanges="orientation"属性,当屏幕旋转时,A不会从新建立, 不会调用onSaveInstanceState 和 onRestoreInstanceState来保存和恢复数据,仅执行onConfigurationChanged
AndroidManifest.xml
<activity android:name=".app_component.activity.lifecycle.A" android:configChanges="orientation"/>
A.java
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // 2 == ORIENTATION_LANDSCAPE // 1 == ORIENTATION_PORTRAIT // 0 == ORIENTATION_UNDEFINED Log.d(TAG, "onConfigurationChanged, newOrientation:" + newConfig.orientation); }
D/A: onConfigurationChanged, newOrientation:1 D/A: onConfigurationChanged, newOrientation:2 D/A: onConfigurationChanged, newOrientation:1
经过设置setRequestedOrientation设置为横屏或竖屏。
这种方式,屏幕不会旋转,什么函数也不会调用,Activity不销毁并从新建立。
DisableRotateActivity.java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { setTitle(R.string.activity_disable_Rotate); super.onCreate(savedInstanceState); // 禁止横竖屏转换,设置屏幕方向为竖屏 //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // 禁止横竖屏转换,设置屏幕方向为横屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }
DisableRotateActivity.java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { setTitle(R.string.activity_disable_Rotate); super.onCreate(savedInstanceState); // 手机时,竖屏; 平板时,容许转屏,容许从新建立Activity boolean isTablet = isTablet(); Log.d(TAG, "onCreate: isTablet=" + isTablet); setRequestedOrientation(isTablet ? ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } private boolean isTablet() { String screen = getString(R.string.screen); Log.d(TAG, "isTablet: screen=" + screen); return ("xlarge-land".equalsIgnoreCase(screen) || "xlarge".equalsIgnoreCase(screen)); }
// 启动,就是横屏 D/DisableRotateActivity: isTablet: screen=xlarge-land D/DisableRotateActivity: onCreate: isTablet=true D/DisableRotateActivity: onStart D/DisableRotateActivity: onResume // 横屏 -> 竖屏 D/DisableRotateActivity: onConfigurationChanged: 1 D/DisableRotateActivity: onConfigurationChanged: ORIENTATION_PORTRAIT D/DisableRotateActivity: onPause D/DisableRotateActivity: onSaveInstanceState D/DisableRotateActivity: onStop D/DisableRotateActivity: onDestroy D/DisableRotateActivity: isTablet: screen=xlarge D/DisableRotateActivity: onCreate: isTablet=true D/DisableRotateActivity: onStart D/DisableRotateActivity: [onRestoreInstanceState]restore extra_test:test D/DisableRotateActivity: onResume // 竖屏 -> 横屏 D/DisableRotateActivity: onConfigurationChanged: 2 D/DisableRotateActivity: onConfigurationChanged: ORIENTATION_LANDSCAPE D/DisableRotateActivity: onPause D/DisableRotateActivity: onSaveInstanceState D/DisableRotateActivity: onStop D/DisableRotateActivity: onDestroy D/DisableRotateActivity: isTablet: screen=xlarge-land D/DisableRotateActivity: onCreate: isTablet=true D/DisableRotateActivity: onStart D/DisableRotateActivity: [onRestoreInstanceState]restore extra_test:test D/DisableRotateActivity: onResume
Activity的优先级按照从高到低的顺序,分为3种:
当系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并在后面调用onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。
当app 没有四大组件在执行,进程会很快被OS(系统)杀死。
内存资源很低时,当把app放在后台,MainActivity就被销毁了,可是app进程还在。过了2分钟,app进程也被杀死了。
Force Stop,app 进程被杀死时,not invork any lifecycle function。
从Recent list中重启qpp,app进程?不是原来的进程号,是一个新的进程。
// Open app, A is mainActivity D/A: onCreate: D/A: onStart D/A: onResume // A -> B D/A: onPause D/B: onCreate: D/B: onStart D/B: onResume D/A: onStop // B -> HomeScreen -> Settings -> AppsInfo D/B: onPause: D/B: onSaveInstanceState D/B: onStop: // In AppsInfo app, force Stop My app. app 进程已经杀死了。 // No log . So not invork any lifecycle function. // Reopen app from recent list, 从新重启qpp, app进程不是原来的进程,是一个新的进程。 D/A: onCreate: D/A: onStart D/A: onResume
<video id="video" controls="" preload="none" poster="http://media.w3.org/2010/05/sintel/poster.png"> <p>force Stop My app </p> <source id="mp4" src="https://yingvickycao.github.io/img/android/app_component/activity/life_cycle/force_stop_app_video_1.mp4" type="video/mp4"> <source id="mp4" src="https://yingvickycao.github.io/img/android/app_component/activity/life_cycle/force_stop_app_video_2.mp4" type="video/mp4"> </video>