1. 程式人生 > >activity長時間後臺的回收重建

activity長時間後臺的回收重建

Android系統的回收機制會在未經使用者主動操作的情況下銷燬activity(比如長時間後臺執行),而為了避免系統回收activity導致資料丟失,Android為我們提供了onSaveInstanceState(Bundle outState)和onRestoreInstanceState(Bundle savedInstanceState)用於儲存和恢復資料。

當Activity後臺被回收後,再次開啟App,Acitivity會執行空參的建構函式,在該函式中的初始化操作會生效,而在Fragment中,再執行建構函式的同時會執行onAttach和onCreate方法,所以onAttach和onCreate中的初始化會生效。

一、onSaveInstanceState(Bundle outState) 
當activity被系統自動回收的情況下,且是在onStop()之前會呼叫該方法,另外,如果activity是使用者主動銷燬,比如按下back返回鍵或者是呼叫finish方法,onSaveInstanceState就不會被呼叫。

總結下,onSaveInstanceState(Bundle outState)會在以下情況被呼叫: 
1、當用戶按下HOME鍵時。 
2、從最近應用中選擇執行其他的程式時。 
3、按下電源按鍵(關閉螢幕顯示)時。 
4、從當前activity啟動一個新的activity時。 
5、螢幕方向切換時(無論豎屏切橫屏還是橫屏切豎屏都會呼叫)。 

在這些情況下,該方法的呼叫時機都是在onPause和onStop方法之間:onPause -> onSaveInstanceState -> onStop。

二、onRestoreInstanceState(Bundle saveInstanceState)onRestoreInstanceState(Bundle savedInstanceState)只有在activity確實是被系統回收,重新建立activity的情況下才會被呼叫。

比如第5種情況螢幕方向切換時,activity生命週期如下: 
onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume

 
在這裡onRestoreInstanceState被呼叫,是因為螢幕切換時原來的activity確實被系統回收了,又重新建立了一個新的activity。 
(順便吐槽一下網上的那些文章說橫屏切豎屏和豎屏切橫屏時activity生命週期方法執行不一樣,經自己實踐證明是一樣的。)

而按HOME鍵返回桌面,又馬上點選應用圖示回到原來頁面時,activity生命週期如下: 
onPause -> onSaveInstanceState -> onStop -> onRestart -> onStart -> onResume 
因為activity沒有被系統回收,因此onRestoreInstanceState沒有被呼叫。

如果onRestoreInstanceState被呼叫了,則頁面必然被回收過,則onSaveInstanceState必然被呼叫過。

三、onCreate()裡也有Bundle引數,可以用來恢復資料,它和onRestoreInstanceState有什麼區別?

因為onSaveInstanceState 不一定會被呼叫,所以onCreate()裡的Bundle引數可能為空,如果使用onCreate()來恢復資料,一定要做非空判斷。

而onRestoreInstanceState的Bundle引數一定不會是空值,因為它只有在上次activity被回收了才會呼叫。

而且onRestoreInstanceState是在onStart()之後被呼叫的。有時候我們需要onCreate()中做的一些初始化完成之後再恢復資料,用onRestoreInstanceState會比較方便。下面是官方文件對onRestoreInstanceState的說明:

This method is called after onStart() when the activity is being re-initialized from a previously saved state, given here in savedInstanceState. Most implementations will simply use onCreate(Bundle) to restore their state, but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation.
  • 1

注意這個說明的最後一句是什麼意思? 
to allow subclasses to decide whether to use your default implementation.

它是說,用onRestoreInstanceState方法恢復資料,你可以決定是否在方法裡呼叫父類的onRestoreInstanceState方法,即是否呼叫super.onRestoreInstanceState(savedInstanceState); 
而用onCreate()恢復資料,你必須呼叫super.onCreate(savedInstanceState); 
否則執行會報如下錯誤:

E/AndroidRuntime(4964): android.util.SuperNotCalledException: Activity {com.example.test/com.example.test.SecondActivity} did not call through to super.onCreate()E/AndroidRuntime(4964): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2331)E/AndroidRuntime(4964): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2426)E/AndroidRuntime(4964): at android.app.ActivityThread.access$800(ActivityThread.java:153)E/AndroidRuntime(4964): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1345)E/AndroidRuntime(4964): at android.os.Handler.dispatchMessage(Handler.java:110)E/AndroidRuntime(4964): at android.os.Looper.loop(Looper.java:193)E/AndroidRuntime(4964): at android.app.ActivityThread.main(ActivityThread.java:5386)E/AndroidRuntime(4964): at java.lang.reflect.Method.invokeNative(Native Method)E/AndroidRuntime( 4964): at java.lang.reflect.Method.invoke(Method.java:515)E/AndroidRuntime(4964): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829)E/AndroidRuntime(4964): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)E/AndroidRuntime(4964): at dalvik.system.NativeStart.main(Native Method)--------- beginning of /dev/log/main