【Android】安卓四大元件之Activity(二)
前言
在這篇文章之前,我已經寫過了一篇有關Activity的內容,是關於activity之間的頁面跳轉和資料傳遞,而這篇文章著重強調的是Activity中的有關生命週期的理解。
1、什麼是生命週期?
在之前學習Java的時候,Java中的一個類的物件就涉及到了生命週期,包括它的生成、作用、回收等等。
在Android中也有差不多的生命週期的概念,是針對Activity
的。
首先,給出安卓開發文件中對生命週期的介紹:瞭解 Activity 生命週期
在官方文件的基礎上,我們來理解各個生命週期!
當使用者瀏覽、退出和返回到您的應用時,應用中的 Activity
例項會在其生命週期的不同狀態間轉換,而為了在 Activity 生命週期的各個階段之間導航轉換,Activity 類提供六個核心回撥:onCreate()
、onStart()
、onResume()
、onPause()
、onStop()
和 onDestroy()
。當 Activity 進入新狀態時,系統會呼叫其中每個回撥。
以下是官方文件對六大生命週期回撥方法
的簡化檢視:
2、onCreate()
2.1 基本解析
因為生命週期是從上向下執行的,我們首先分析最開始的onCreate()
方法
onCreate()
,這個是activity被首次建立的時候呼叫的方法,而且我們必須在每個activity中重寫該方法!這個方法在activity生命週期中只出現一次,如果第二次出現,那麼說明上一個activity已經呼叫了onDestroy()方法,被銷燬了。
相信你對下面的程式碼不陌生,因為每個activity中都會有這樣類似作用的程式碼!
private TextView photo;
private ImageView pic;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
photo = this.findViewById(R.id.tv_photograph);
pic = this.findViewById(R.id.iv_pic);
photo.setOnClickListener(this);
}
在開始構建activity的時候,我們在onCreate()
方法中我們都會會將資料繫結
到列表,將 Activity與各個元件相關聯,並例項化
某些類作用域變數。
我們在上述的程式碼例子中可以發現,我們例項化了photo這個TextView
還有pic這個ImageView
,並且在此之前,我們一定會給當前這個activity繫結一個xml佈局檔案,通過呼叫setContentView()
方法,然後通過R.layout
找到我們需要的佈局xml進行繫結。
2.2 你可能疑惑的savedInstanceState
以下內容感興趣的可以看看,初學者如果不明白其實也不需要太懂。
細心的你會發現,onCreate()其實傳入了一個Bundle
類的物件引數savedInstanceState
,這是個啥玩意?
接下來,我們對savedInstanceState進行詳細解釋!
首先我們分析以下Bundle
類是啥,說通俗一點,就是實現了Parcelable
介面的一個鍵值對
官方的簡介是:
A mapping from String keys to various
Parcelable
values.
也就是說,這個類例項化的物件是可以儲存資料
的,並且是以鍵值對
的形式儲存的,實現了Parcelable
介面
而傳入的savedInstanceState
物件,字面翻譯就是儲存過的例項狀態
,並且我們上面說了,savedInstanceState
都物件可以儲存鍵值對,也就是說有兩種情況:
savedInstanceState
不為nullsavedInstanceState
是null的
事實上,savedInstanceState
為null的情況是最常見的,但是什麼情況savedInstanceState
不為空呢?
2.2.1 onSaveInstanceState()方法
根據文件,我們發現,Activity類中有一個onSaveInstanceState()
方法,不同於onCreate()
這種生命週期方法,onSaveInstanceState()
只有在進入某種“activity有被殺死的風險”的狀態下,才會被呼叫
會執行onSaveInstanceState()
方法的情況,官方文件中是如下解釋的:
Android calls onSaveInstanceState() before the activitybecomes vulnerable to being destroyed by the system, but does not bothercalling it when the instance is actually being destroyed by a user action (suchas pressing the BACK key).
當某個activity變得"容易"被系統銷燬時,該activity的onSaveInstanceState()就會被執行,除非該activity是被使用者主動銷燬的,例如當使用者按BACK鍵的時候。
通俗一點,就是進入某種“activity有被殺死的風險”狀態,onSaveInstanceState()
方法就會被呼叫
也許你想到了很多的情況,我總結了一共如下的情況會呼叫onSaveInstanceState()
方法:
- 當使用者按下HOME鍵後。(這種情況,系統不知道你按下HOME後要執行多少其他的程式,自然也不知道activity A是否會被銷燬,因此係統會呼叫
onSaveInstanceState()
,讓使用者有機會儲存某些非永久性的資料) - 調出程式管理,選擇執行其他的程式時。(同樣是可能記憶體不夠被系統kill掉)
- 按下息屏鍵關閉螢幕時(一樣的道理,手機廠家會設定息屏後程式的狀態,也可能被kill)
- 從activity A中啟動一個新的activity B時。(例如從QQ開啟某tx遊戲,遊戲的資源呼叫很大,可能把QQ的程式kill掉,雖然大多數情況我們是給QQ後臺許可權的)
- 螢幕方向切換時,例如從豎屏切換到橫屏時。(在螢幕切換時,系統會銷燬activity A,在螢幕切換之後系統又會自動地建立activity A,所以
onSaveInstanceState()
一定會被執行,且也一定會執行onRestoreInstanceState()
)
說專業一點:只要某個Activity是做入棧並且非棧頂
時(啟動跳轉其他Activity或者點選Home按鈕),此Activity是需要呼叫onSaveInstanceState()
的, 如果Activity是做出棧
的動作(點選back或者執行finish),是不會呼叫onSaveInstanceState
的。
2.2.2 onRestoreInstanceState()方法
與onSaveInstanceState()
對應的是onRestoreInstanceState()
方法,但是——這兩個方法並不是成對出現,執行了``onSaveInstanceState()不一定執行
onRestoreInstanceState()`
onRestoreInstanceState()
執行的條件是:只有在Activity真的被系統非正常殺死過,恢復顯示Activity的時候,就會呼叫onRestoreInstanceState()
簡單來說,執行了onSaveInstanceState()儲存了資料狀態,並不一定會呼叫onRestoreInstanceState()來返回狀態,但是如果確實時非正常的kill程式,那麼會呼叫onRestoreInstanceState()返回onSaveInstanceState()儲存的資料
我們可以看看安卓開發文件中給出的例子:
TextView textView;
// some transient state for the activity instance
String gameState;
@Override
public void onCreate(Bundle savedInstanceState) {
// call the super class onCreate to complete the creation of activity like
// the view hierarchy
super.onCreate(savedInstanceState);
// recovering the instance state
if (savedInstanceState != null) {
gameState = savedInstanceState.getString(GAME_STATE_KEY);
}
// set the user interface layout for this activity
// the layout file is defined in the project res/layout/main_activity.xml file
setContentView(R.layout.main_activity);
// initialize member TextView so we can manipulate it later
textView = (TextView) findViewById(R.id.text_view);
}
// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}
// invoked when the activity may be temporarily destroyed, save the instance state here
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(GAME_STATE_KEY, gameState);
outState.putString(TEXT_VIEW_KEY, textView.getText());
// call superclass to save any view hierarchy
super.onSaveInstanceState(outState);
}
可以看到重寫的onSaveInstanceState()
方法中存入了遊戲狀態
和textView
的文字,在onRestoreInstanceState()
方法中,呼叫了獲取當前文字並設定
的方法,並且我們可以在這個例子中看到onCreate()
方法中是如何利用savedInstanceState
這個物件的——不為空那麼就獲取資料
if (savedInstanceState != null) {
gameState = savedInstanceState.getString(GAME_STATE_KEY);
}
3、onStart()
當 Activity 進入“onStart”狀態時,系統會呼叫onStart()
方法。onStart()
呼叫使 Activity 對使用者可見,也就是在這個方法中,我們可以看到app的前端activity展示了
onStart()
方法會非常快速地完成,並且與onCreate()一樣,Activity 不會一直處於“onStart”狀態。一旦此回撥結束,Activity 便會進入“onResume”狀態,系統將呼叫 onResume()
方法。
4、onResume()
onResume
是應用與使用者互動的狀態,也就是具有焦點,我們可以對app中的各種元件進行操作的一個焦點狀態,這個時候是使用者與應用的互動的狀態。
5、onPause()
onPause
狀態是使用者對這個activity失去焦點
,但是onPause這個狀態,使用者還是對activity可見
的。
舉個例子,有兩個activity,第一個activity A,第二個activity B。
如果A使用透明主題
,B使用預設主題。當由A通過Intent跳轉到B時,會失去A的焦點,呼叫onPause()
方法,但是,因為時透明主題,所以我們在看B的同時,可以看到A,也就是A仍然是可見的,所以A不會呼叫onStop()
,也就是不會被停止
如果這個時候我們點選back
按鈕,從B返回到了A,A會重新呼叫onResume()
方法,因為A得到了焦點
,但是並不會呼叫onStart()
,因為我們的A從來沒有被停止過
,仍然有可見的介面
6、onStop()
onStop
狀態就是我們對這個activity失去了焦點,但是它並未被銷燬
舉一個常見的例子——微信掃一掃
,我們從微信主頁開啟微信掃一掃,主頁失去了焦點
並且不可見
,成為了onStop
的狀態,返回
之後主頁又得到了焦點
,執行了onStart()
和onResume()
7、onDestroy()
onDestroy
被執行,呼叫此回撥的原因如下:
- Activity 即將結束(由於使用者
徹底關閉
Activity或由於系統為Activity呼叫finish()
方法 - 由於配置變更(例如
裝置旋轉
或多視窗模式
),系統暫時銷燬Activit
如果Activity即將結束,onDestroy()
是 Activity 收到的最後一個生命週期回撥。如果由於配置變更而呼叫 onDestroy(),系統會立即新建 Activity 例項,然後在新配置中為新例項呼叫onCreate()
8、橫豎屏的影響
在理解了各個部分的生命週期之後,我們應該注意到,在APP中橫豎屏的切換,會導致生命週期改變——先銷燬、再建立一個新的。
那麼我們可能遇到這樣的情況——我們豎屏看電影的時候,進度條在20分鐘,但是如果我們切換成了橫屏進度條就從頭開始了。這種APP出現的問題就是沒有處理橫豎屏切換帶來的影響。
之所以會出現上述情況,是因為activity的一個生命週期已經結束了,橫屏進入了一個新的生命週期。
解決方法有兩種:
- 在activity中設定
android:screenOrientation="landscape"
,這樣APP始終保持在橫屏。 - 在activity中設定
android:configChanges="keyboardHidden|screenSize|orientation"
,這樣activity在“鍵盤隱藏”、“螢幕大小變化”、“橫豎屏切換”的時候,不會產生影響。
一般遊戲開發使用第一種方法,因為遊戲需要一直橫屏。電影播放等使用第二種方法,這樣就可以保持橫豎屏進度條一致啦!
後話
關於Android中的activity中生命週期
的理解到此結束了,之後還有對activity的啟動模式
的分析!
建議搭配安卓開發文件進行觀看,文章內容僅供參考!