Android之Handling Runtime Changes(處理運行時更改)

來源:互聯網
上載者:User

一些裝置配置在運行過程中可能會發生改變(例如螢幕橫向布局、鍵盤可用性和語言)。當這樣的變化發生時,Android會重新啟動這個正在啟動並執行Activity(onDestroy()方法會被調用,然後調用onCreate()方法)。這個重啟的動作是為了通過自動往你的應用程式中載入可替代資源,從而使你的應用適應新的配置。

為了正確執行一次重啟,你的Activity在整個平凡的生命週期中重新儲存它之前的狀態是很重要的,Android是通過在銷毀你的Activity之前調用onSaveInstanceState()方法來儲存關於應用之前狀態的資料。然後你就可以在onCreate()方法或者onRestoreInstanceState()方法中重新儲存應用的狀態了。為了測試你的應用可以通過應用的狀態原封不動地重啟自己,你應該給你的應用授權當程式在執行不同的任務時應用的配置可以改變(例如螢幕的方向變化)。

為了處理一些事件,例如當使用者接聽一個打入的電話然後返回到你的應用程式中,在沒有丟失使用者資料或者狀態資訊的情況下,你的應用應該具備在任何時候重啟自己的能力(更多參見Activity lifecycle)。

然而,你可能要面對這樣一個情景,重啟你的應用程式並重新儲存大量有價值的資料會導致很差的使用者體驗。在這樣的情景面前,你有兩種選擇:

a     在配置改變期間維持一個對象

當配置發生改變時允許你的Activity重啟,但讓其攜帶一個有狀態的對象到你的新Activity執行個體中。

b     你自己來處理配置的變化

當某些配置發生變化的時候阻止系統重啟你的Activity,並且當配置改變時要接收一個回調,這樣你就可以根據需要來手動更新你的Activity。

在配置改變期間維持一個對象

如果重啟你的Activity,你需要恢複大量的資料,重新執行網路連接,或者其他深入的操作,這樣由配置改變引起的一次完全啟動就會引起不好的使用者體驗。而且,僅有Activity生命週期中為你儲存的的Bundle對象,你是不可能完全維護你的Activity的狀態的—不能傳遞很大的對象(如bitmap對象),並且這些對象裡面的資料必須序列化,然後解序列化,這些都需要消耗很多記憶體從而使配置改變得很慢。在這樣的情境下,當你的Activity由於配置發生改變而重啟時,你可以通過重新預置一個有狀態的對象來減緩你程式的負擔。

在運行期間配置改變時維護一個對象:

1.      重寫 onRetainNonConfigurationInstance() 方法來返回你想要維護的對象

2.      當你的Activity再次建立時,調用getLastNonConfigurationInstance()方法恢複你的對象

當你的Activity由於配置發生改變要關閉的時候,Android會在執行onStop()方法與onDestroy()方法之間調用onRetainNonConfigurationInstance()方法。為了在配置改變後更有效地儲存狀態,在實現onRetainNonConfigurationInstance() 方法時你應該返回你所需要的一個對象。

這個情境的可貴之處在於當你的應用程式需要從網上下載很多資料的時候。如果使用者更改裝置的方向並且Activity重啟,你的應用程式必須要重新載入資料,那就會很慢了。你需要做的就是實現onRetainNonConfigurationInstance() 方法並返回帶有你的資料的對象,然後當你的 Activity通過getLastNonConfigurationInstance()方法重啟時就能擷取資料。例如:

@Override
public Object onRetainNonConfigurationInstance() {
    final MyDataObject data = collectMyLoadedData();
    return data;
}

特別提醒:當你要返回任何對象的時候,你應該不要傳遞一個跟Activity有關聯的對象,例如一個Drawable對象,一個Adapter對象,一個View對象或者任何其他跟Context相關的對象 。如果你這樣做,它會泄漏原來Activity執行個體的所有視圖和資源。(泄漏資源意味著您的應用程式保持對他們的持有,他們不能被當做垃圾收集,因此記憶體就丟失了)

然後當你的Activity重啟時擷取資料:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();
    if (data == null) {
        data = loadMyData();
    }
    ...
}

這個例子中,getLastNonConfigurationInstance()擷取了onRetainNonConfigurationInstance()方法中儲存的資料。如果資料為空白,(這種情況發生在,當Activity重啟是由其他原因而不是配置改變引起的)那麼程式將從原來的資料來源載入資料對象 。

 

 

 

你自己來處理配置的變化

如果在某個特殊的配置發生改變的期間你的應用程式不需要更新資源,而且你有個操作限制需要你避免Activity的重啟,那麼你可以聲明使你自己的Activity來處理配置的變化,從而阻止系統重啟你的Activity。

特別提醒: 選擇自己來處理配置的變化會使得可替代資源的使用變得更困難,因為系統不會為你來自動調用這些資源。這種技術應該被視為最後的手段,對於大多數應用程式不建議使用。

為了聲明你的Activity來處理配置的變化,在資訊清單檔中編輯正確的<activity>元素,包括賦好值的android:configChanges屬性,代表你要處理的配置。android:configChanges屬性所有可能的值都要在文檔中列出(最常用的值是:orientation來處理當螢幕的方向變化時,keyboardHidden來處理鍵盤可用性改變時)。你可以在屬性中聲明多個配置的值,通過“|”符號將它們分隔開。

例如,以下清單片段聲明了Activity中將同時處理螢幕的方向變化和鍵盤的可用性變化:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

當這些配置中的一個發生改變時,MyActivity不會重新啟動。相反,這個 Activity會接收onConfigurationChanged()方法的調用。這個方法傳遞一個Configuration類的對象來標識新的裝置配置。通過讀取配置欄位,你可以確定新的配置資訊並通過更新你介面中使用的資源來正確應用這些改變。任何時候這個方法被調用,你的Activity的Resources對象會被更新並返回一個基於新配置的Resources對象,因此你可以在不用系統重啟你的Activity的情況下很容易地重設你的UI元素。

例如,接下來的onConfigurationChanged()方法中實現了檢查硬體鍵盤的可用性和當前裝置的方向:

@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();
    }
    // Checks whether a hardware keyboard is available
    if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
        Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
    } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
        Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
    }
}

這個Configuration類的對象代表著當前所有的配置資訊,不僅僅那些改變的配置資訊。在很多時候,你不會確切地在乎這些配置是怎麼改變的,並且可以簡單地重新分配所有資源,提供您正在處理的配置的可替代資源。例如,因為這個Resources對象現在被更新,你可以通過setImageResource(int)方法重設任何ImageView,並重設恰當的資源給當前配置使用。(詳見:Providing Resources

請注意,配置欄位的值是一些匹配Configuration類裡特定的常量的整數。對於文檔中的每個欄位使用那個常量,請在Configuration類中參閱相應的欄位。

記住:當你聲明你的Activity來處理配置的變化時,你負責重設所有你提供可替代資源的元素 。如果你聲明你的Activity來處理螢幕方向的改變並具有在橫向和縱向之間切換的映像,你必須在onConfigurationChanged()方法中給每個元素重新指定一個資源。

如果你不需要根據配置的變化來更新你的程式,你可以不實現onConfigurationChanged()方法。在這種情況下,所有在配置改變之前使用的資源仍然會被使用,並且你只需要避免你的Activity被重啟。然而,您的應用程式應該始終能夠關閉並從其之前的狀態完好地重新啟動。這不僅是因為存在有一些配置發生改變時你不能防止它重新啟動您的應用程式,而且為了處理一些事件,例如當使用者接收了電話然後返回到應用程式。

更多關於哪些配置變化時你可以在你的Activity中處理,參見android:configChanges文檔和Configuration類。

 

 

 

歡迎轉載,轉載請註明出處http://www.cnblogs.com/CodeGuy/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.