這篇文章要記錄onSaveInstanceState以及onRestoreInstanceState的使用,小蛙其實對這個部分了解還不是很透徹,但是小蛙的做法的確是可以work,供大家做個參考囉!

照照明星臉上架以來直到現在(好慚愧),一直無法擺脫拍完照片,或是從相簿選取圖片後無法使用的情況(有些是Force Close, 有些是直接跳回主畫面沒有任何反應),這裡面的問題有很多,是小蛙一開始不太能夠完全掌握相機及相簿的使用造成的,後來慢慢的大部分的機種都可以正常使用,卻面臨到同樣機種的手機,有些可以正常使用,有些卻無法使用,例如:HTC Sensation有使用者回報正常使用,卻也有回報無法使用 … 同樣的最近小蛙面臨到的是 SE Arc S。
小蛙的同事昨天跟小蛙說,他的Arc S沒有辦法使用明星臉,跟上面敘述的是一樣的問題,小蛙借了他的Arc S測試後發現,拍照前建立的tmpFile以及傳給相機的imageUri,在最後onActivityResult回來後全部都變成null,小蛙百思不得其解啊!為什麼回到主畫面之後會變成null,直到看到這篇stackoverflow的文章,文章的標題雖然看起來沒關係,但jeffamaphone的回應幫了小蛙大忙!

onSaveInstanceState跟onRestoreInstanceState的官方說明如下(截錄自Activity | Android Developers):

protected void onSaveInstanceState (Bundle outState)

Called to retrieve per-instance state from an activity before being killed so that the state can be restored in onCreate(Bundle) or onRestoreInstanceState(Bundle) (the Bundle populated by this method will be passed to both).
This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state. For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(Bundle) or onRestoreInstanceState(Bundle).
Do not confuse this method with activity lifecycle callbacks such as onPause(), which is always called when an activity is being placed in the background or on its way to destruction, or onStop() which is called before destruction. One example of when onPause() and onStop() is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState(Bundle) on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause() is called and not onSaveInstanceState(Bundle) is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState(Bundle) on activity A if it isn’t killed during the lifetime of B since the state of the user interface of A will stay intact.
The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id, and by saving the id of the currently focused view (all of which is restored by the default implementation of onRestoreInstanceState(Bundle)). If you override this method to save additional information not captured by each individual view, you will likely want to call through to the default implementation, otherwise be prepared to save all of the state of each view yourself.
If called, this method will occur before onStop(). There are no guarantees about whether it will occur before or after onPause().

protected void onRestoreInstanceState (Bundle savedInstanceState)

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. The default implementation of this method performs a restore of any view state that had previously been frozen by onSaveInstanceState(Bundle).
This method is called between onStart() and onPostCreate(Bundle).

看得懂的就看,看不懂的google一下,對岸有很多網站對於這兩個function都有翻譯。小蛙這邊直接講照照明星臉相機及相簿無法使用的原因。
點選從使用相機拍照及從相簿選擇的同時,小蛙先建了一個tmpFile,在丟入相機的參數中增加imageUri = Uri.fromFile(tmpFile);,正常情況下若從相簿挑選照片回來,小蛙會把得到的相片轉存到tmpFile(如此是為了避免修改或刪除原始照片);假設從相機回來,可以從剛剛設定的imageUri中取得圖片,但偏偏這兩個回來的東西在一台Arc S上面正常,在另一台Arc S上面卻回傳java.lang.NullPointerException。
Override了onSaveInstanceState及onRestoreInstanceState這兩個function印出Log訊息發現,兩台都會呼叫onSaveInstanceState,但是只有其中一台會呼叫onRestoreInstanceState,而這台恰巧就是會發生錯誤的那台。小蛙猜測當使用Intent開啟內建相機時(MediaStore.ACTION_IMAGE_CAPTURE),由於手機內部的記憶體不夠使用,造成照照明星臉主程式必須先暫時關閉,當照相動作完成後才會再回到照照明星臉,這時候照照明星臉之前建立的變數,例如:tmpFile, imageUri。就會變成null解決的方法只要在Override onSaveInstanceState並且在該function中加入要保存的變數及其值,當主控權又回到照照明星臉時再呼叫onRestoreInstanceState把剛剛存起來的值還原,就可以避免掉onActivityResult()中有時候會出現java.lang.NullPointerException,有時候卻又可以正常使用的問題了!

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *