最近做項目的時候碰到一個棘手的問題,花了不少時間才找到原因並解決。特此記錄這個被我踩過的坑,希望其他朋友遇到此問題不要調到這坑里去了。
問題描述:
1、背景:我的app中某個界面的Activity是繼承FragmentActivity,因為此界面包含兩個Fragment。這里我稱為FragmentA和FragmentB吧。在Activity中有個刷新按鈕,用來刷新ViewPager當前Fragment內容的刷新。點擊Activity的刷新按鈕之后,刷新按鈕需要有簡單的旋轉動畫,等Fragment里面的刷新結束之后,會使用getActivity通知Activity結束刷新按鈕的刷新動畫。以上就是我的業務場景,說簡單點就是Fragment需要與它附屬的Activity進行通信。
2、問題:當應用程序運行到該Activity時,按Home鍵將該應用程序放置后台運行,去其他app轉轉。一段時間后,又回到該應用程序,還是在之前的那個Activity。這時我想刷新一下Fragment里面的內容,點擊了Activity界面上的刷新按鈕,結果程序crash了。
問題分析:
剛開始遇到該問題時,查看奔潰日志,發現是空指針異常。因為這種場景不多,所以只是簡單的加上非空判斷就沒在意這個問題了。到后面換了個測試機器,配置不是很好(只有512M運行內存),結果此問題頻繁地出現,開始引起我的重視了。由於經驗不是很足,此問題不知道怎么重現,所以很難找出問題的根本原因。后來終於在網上找到了一篇和我遇到同樣問題的朋友的帖子,才知道出現這個問題的原因所在。
原來Activity切換到后台之后,由於內存不夠,此Activity被系統回收了,一段時間之后回到該應用程序,Activity被重新實例化了。而Activity被系統銷毀時,附屬在該Activity的Fragment並沒有被銷毀,在Activity的onSaveInstanceState里面將Fragment狀態保存起來了,所以Activity重新創建了,但是FragmentA和FragmentB還是之前的,而此時FragmentA和FragmentB所附屬的Activity已經被系統回收了,這次再調用getActivity時返回了null,才導致上面問題的出現。
我們看看FragmentActivity源碼中的onSaveInstanceState方法:
1 protected void onSaveInstanceState(Bundle outState) 2 { 3 super.onSaveInstanceState(outState); 4 Parcelable p = mFragments.saveAllState(); 5 if (p != null) { 6 outState.putParcelable("android:support:fragments", p); 7 } 8 }
由上面源碼可以看出,FragmentActivity確實在onSaveInstanceState方法里面將Fragment的狀態保存了。
問題解決:
知道問題的原因了,就好辦了。解決方法其實很簡單,我們只要讓FragmentActivity被系統回收的時候,不保存Fragment的狀態即可,即在FragmentActivity中重寫onSaveInstanceState方法,並且注釋掉super.onSaveInstanceState(outState)就行了。
1 @Override 2 protected void onSaveInstanceState(Bundle outState) { 3 // super.onSaveInstanceState(outState); 4 }
總結:
1、程序出現問題時,要先找出出現此問題的原因,對症下葯才能從根本上解決問題。
2、對於Activity被系統回收導致的問題,可以使用切換橫豎屏來模擬場景。
最后感謝寫http://my.oschina.net/u/1011854/blog/469138這篇帖子的朋友。