6

在閱讀一本介紹性的Android編程書籍之後,我想修改示例應用程序,以便鞏固我對一些未真正涵蓋的主題的理解。在做出改變時,我犯了一個錯誤,但我很好奇爲什麼錯誤在某些情況下有效,但在其他情況下卻不起作用。爲什麼在onSaveInstanceState()中保存一個非可Parcelable對象的Hashtable有時會工作?

應用程序中的一項活動將一系列問題存儲在Hashtable<Integer, Question>中,其中Question是一個持有int和兩個字符串的小類。如最初所寫,活動每onCreate()下載服務器上的問題,所以我想實施onSaveInstanceState()以防止某些冗餘下載。 onSaveInstanceState()使用putSerializable()將Hashtable保存在Bundle中。

@Override 
protected void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
      // mQuestions is a member variable of 
      // type Hashtable<Integer, Question> 
    if (mQuestions != null && mQuestions.size() > 0) { 
     outState.putSerializable(SAVED_QUESTIONS, mQuestions); 
    } 
} 

即使在我知道Parcelable是什麼或者如何實現之前,它對屏幕方向的改變完美地工作。我只知道有一個問題,當我按下模擬器的主鍵和應用程序時,無聲無息地無視LogCat輸出而崩潰。堆棧跟蹤讓我查看Parcelable並讓Question實現它。

我的問題不是我做錯了什麼。問題是這樣的:當Question類沒有實現Parcelable時,爲什麼應用程序只按下Home而不是屏幕方向更改?

+0

「的onSaveInstanceState()保存使用putSerializable()哈希表入捆綁」。 - 不要將數據模型置於實例狀態。將您的數據模型放入文件或數據庫中。這就是你「防止多餘的下載」。 「只有當我按下模擬器的主鍵和應用程序時才知道存在問題,無聲無息地崩潰,沒有LogCat輸出。」 - 而你對這種沉默無形的崩潰的證明是......究竟是什麼? – CommonsWare 2011-03-03 22:51:47

+0

@CommonsWare:Eclipse中出現一個彈出窗口,要求打開Debug透視圖,因爲啓動已暫停。這就是我知道它墜毀的原因。我已經註釋出了問題可解釋的代碼,並且在一次嘗試中(幾次),它確實強制關閉記錄的錯誤,但是在發佈這個問題之前沒有發生。 – erichamion 2011-03-04 00:44:49

+0

是的,數據真的應該保存到一個文件,但這不是我想要做的。我不是在製作應用程序(即使是個人,愛好使用)。我正在修改通過_Sam的24小時教你自己的Android應用程序開發創建的演示應用程序。即使是一本介紹性的書,它似乎也忽略了一些非常基本的主題。我想看看onSaveInstanceState()是如何工作的。我認爲我現在已經掌握了它的機制,如果不是,什麼時候以及如何最好地使用它。 – erichamion 2011-03-04 00:49:10

回答

1

引用史蒂夫·莫斯利

需要注意的是使用安全onSaveInstanceStateonRestoreInstanceState,根據http://developer.android.com/reference/android/app/Activity.html上的活動狀態的文檔。

文檔狀態(在「活動生命週期」部分):

注意,它保存在onPause() 持久性數據是非常重要的,而不是onSaveInstanceState(Bundle) 因爲以後是不是 生命週期的一部分回調,因此不會在 的文檔中的每種情況下調用 。

換句話說,請將您的保存/恢復代碼置於onPause()onResume()之內!

+0

這對於原始問題的評論會更合適,因爲它不是針對發佈的問題的答案:「...爲什麼應用程序僅在按Home時崩潰,而不是在屏幕方向更改上崩潰?」 – glorifiedHacker 2011-07-15 16:57:55

2

據我瞭解,在配置更改後重新創建活動時,Android不會序列化實例狀態。這就是你的代碼工作的原因。持久對象不需要是可分段的,因爲它們只存在於內存中。

這看起來像是一種優化。 Android知道在這種情況下進程不會被終止,並且不需要將實例狀態保存到文件中。 (理論上這個過程可以在配置更改期間終止,我不知道Android如何解決這個問題)。

但是,當用戶按Home鍵你的應用程序變成背景。如果內存不足,可以終止其進程。 Android需要將活動的狀態保存到文件中,以便將來能夠恢復您的應用及其活動。在這種情況下,實例狀態會真正序列化並保存到持久存儲中。這就是爲什麼你的代碼不起作用。

進程終止可以在任何時候發生,因此您不能依賴某些實現細節。只要讓實例狀態parcelable或serializable,你不會再面臨這個問題。

+0

儘管我自己沒有確認,但這個答案對我來說很有意義(爲什麼當變量仍然存在於內存中時,爲了配置更改序列化某些內容)。這也是迄今爲止唯一的答案,試圖解決由erichamion發佈的原始問題。因此,我將賞金獎給這個答案。 – glorifiedHacker 2011-07-15 16:53:24

0

該應用沒有崩潰。當用戶單擊Home鍵時,它就會關閉。這就是爲什麼LogCat沒有輸出。

在Activity.onDestroy()中設置一個斷點來確認這一點。如果我正確onDestroy()將被調用,但onSaveInstanceState()不會,因爲onSaveInstanceState()僅在應用程序處於後臺狀態時調用,而不是在關閉時調用。

如果您需要在關閉時保存應用程序狀態,請將代碼放在onDestroy()中並將其保存爲比Bundle更持久的內容。

百里

相關問題