Android Screen Orientation Event螢幕方向處理+Acitivity Liftcycle

前幾篇文章中介紹了 使用Activity取代TabActivity 以及 透過ActivityGroup達到TabHost中切換Activity。之後會再補上使用 FragmentActivity + Fragment + TabHost 的作法 (Google 建議使用 Fragment)。這篇文章小蛙要記錄當使用者螢幕方向改變時的處理方式。
在發表完上面兩篇文章後,小蛙馬上實作看看使用 FragmentActivity 的方法,實作上面跟 ActivityGroup 差不多,勝過 ActivityGroup 的部分在於有自動維護的 BackStack,不用再自行建立 ArrayList<View> history 來管理 BackStack。至於為什麼沒有馬上發表文章呢?是因為小蛙想要把螢幕方向這件事情一起處理掉再發表,目前的情況是這樣的:

orientation Android Screen Orientation Event螢幕方向處理+Acitivity Liftcycle

問題1.

使用者在 portrait 時切換到 Tab 2,翻轉螢幕成 landscape 時卻回到 Tab 1 (應該要停在 Tab 2)。

問題2.

軟體啟動時為 portrait(A),使用者在 Tab 1 先後運行了 Page1-1、Page1-2、Page1-3,在 Tab2 也同樣運行了 Page2-1 ~ Page2-4,這時候使用者翻轉螢幕變成landscape(B),BackStack 全部被清光光,使用者看到的畫面變成軟體剛啟動時的空白畫面。

針對問題1小蛙直接使用 onSaveInstanceState, onRestoreInstanceState使用 這個方法複寫了 onRestoreInstanceState onSaveInstanceState 兩個方法。

01
02
03
04
05
06
07
08
09
10
11
12
13
@Override
protected void onSaveInstanceState(Bundle outState) {
    // 發生翻轉動作的時候將目前頁籤儲存到Bundle中
    outState.putInt("which", tabHost.getCurrentTab());
    super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // 把剛剛存的取出來
    if(savedInstanceState != null)
        tabHost.setCurrentTab(savedInstanceState.getInt("which"));
    super.onRestoreInstanceState(savedInstanceState);
}

但是今天發現了一個新的東西叫作「android:configChanges」,這應該算是一個蠻基礎的設定,小蛙真是太失敗了…下面這個設定方法可以一併解決上述問題 1,2,也就是說上面的方法不需要用到。用小蛙簡單白話的說明就是:

當使用者翻轉螢幕時,就歷經了一次舊 Activity 的死亡及新 Activity 的誕生,透過 android:configChanges 可以使得翻轉螢幕的動作不用歷經這一個過程,取而代之的是呼叫 onConfigurationChanged 方法。

好吧!總而言之就是只要在 AndroidManifest.xml 的 Activity 敘述中加入android:configChanges=”orientation”,如此一來,當發生螢幕翻轉事件的時候,就可以保留各個 Tab 的狀態以及 BackStack 囉!另外可以透過複寫 onConfigurationChanged 方法來做更進一步的處理。例如官方範例:

01
02
03
04
05
06
07
08
09
10
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

附上 Android Activity Lifecycle 圖 (圖片來源:http://developer.android.com/reference/android/app/Activity.html)。
activity lifecycle Android Screen Orientation Event螢幕方向處理+Acitivity Liftcycle
由於小蛙看到 横竖屏切换时候Activity的生命周期 @ Android开发教程 ( http://android.tgbus.com/Android/tutorial/201103/346550.shtml 連結已失效) 及 【亲测】Activity中的 ConfigChanges 属性以及横竖屏切换时候 Activity 的生命周期 @ 漫步云端 (http://www.cnblogs.com/charley_yang/archive/2011/04/17/2018940.html 連結已失效) 這兩篇文章中的 Lifecycle 感覺有點奇怪,於是自己測了一下,所得到的結果似乎不太一樣,可能是模擬器的行為跟手機的不同,也有可能是 Android 版本不同 (小蛙是用 HTC Desire + MIUI2.3 測試的,android:minSdkVersion=”4″),以下是測試結果供參考。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
// 正常啟動Activity
onCreate
onStart
onResume
// 結束Activity
onPause
onStop
onDestroy
// 翻轉螢幕(直轉橫、橫轉直)
onSaveInstanceState
onPause
onStop
onDestroy
onCreate
onStart
onRestoreInstanceState
onResume
// 翻轉螢幕(直轉橫、橫轉直)
// 以及android:configChanges="orientation"
onConfigurationChanged

今天用模擬器測試了一下,android:configChanges=”orientation” 在模擬器上沒法正常使用,必須要改成 android:configChanges=”orientation|keyboardHidden”,有遇到問題的網友不妨試試看。

最後memo一下,小蛙在官網連結中看到 onRetainNonConfigurationInstance 這個東西,查了三篇文章大概看了一下內容看起來應該蠻實用的,之後有空實作完再把結果Post上來。

[Android] 煩人的螢幕旋轉 @ 生活藝術 ● 藝術生活
activity状态的保存和保持(onRetainNonConfigurationInstance和getLastNonConfigurationInstance) @ chengbs
[Android] 比較onSaveInstanceState() 與 onRetainNonConfigurationInstance() 函式 @ 我思故我在

    發佈留言

    發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

    這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料