在安卓開發中,由於旋轉設備會造成配置改變進而導致Activity實例被摧毀(當然也包括Activity托管的Fragment)。Activity或Fragment實例被摧毀自然也就讓Model被摧毀,數據也就沒有了。這是我們不想看到的。因此有了重寫Activity或者Fragment的onSavedInstanceState(Bundle)方法來保存Model。
通過上述的這種方法的確可以解決一部分數據被摧毀的問題,但是有些數據我們需要一直保持,而非摧毀->重建。比如聽音樂聽得好好的,我旋轉設備,程序員通過onSavedInstanceState(Bundle)方法把音樂保存了,然后onCreate(Bundle)再來將剛剛摧毀的音樂放出來,這可以么?當然不行,你說你吃着火鍋唱着歌,就旋轉個屏幕,音樂突然就沒了,然后嘿又好了,你不罵這個app開發者傻逼我都看不下去!因此有了一個新需求,在設備旋轉等配置改變的情況下我們要讓model一直在,而不是摧毀->重建。這個想想好像無從下手,其實不難。我們可以跳出保存Model的思路,而是直接讓存放Model的Fragment就不會死,那不就行了。
講完了為何,再來說如何保存Fragment實例。
我們只需要重寫Fragment.onCreate()方法,加上setRetainInstance(true)就行了
知其然須知其所以然,我們應該對系統是如何保存了fragment實例的工作原理也要了解。
如果不寫setRetainInstance(true)這句話會發生什么呢?
如上圖所示,由於旋轉完屏幕,設置被改變,FragmentManager會首先銷毀隊列中fragment的視圖,為什么要銷毀它們的原因也很簡單,新的配置可能對應新的資源,當有更適合的新資源匹配時,需要更換成新視圖。然后FragmentManager會依次檢查fragment實例的retainInstance值,如果為false立即銷毀fragment實例。然后眾所周知,會有一個新的Activity創建一個新的FragmentManager來創建新的Fragment實例及其視圖。
但是如果fragment實例的retainInstance值為true,就不會被銷毀。當新的Activity創建新的FragmentManager時,會找到這個被保存的fragment實例,並重新創建它的視圖。
這個"不會死"的fragment,在activity被摧毀時處於被保留狀態,此時沒有任何activity托管它(因為托管它的activity被摧毀了)。
再來看看fragment的生命周期,加深理解。
從上面大段的講述,我們可以總結出fragment需要有如下兩個條件才能進入被托管狀態。
1.它的retainInstance值為true
2.托管它的activity正在被摧毀
等到activity重建,fragment被納入麾下,被保留狀態也就結束了。
再來比較一下onSaveInstance方法和保留fragment實例方法
先看圖:
由圖可得出,在進程關閉時(通常可能發生在用戶暫時離開當前應用以及系統需要回收內存從而銷毀了activity以及被保留的fragment實例時),fragment依然會被摧毀。
因此在需要將數據保存時間和activity記錄一樣長時,並且無需連貫保持(至少表面看不出來是斷掉的)的情況時,最好采用onSaveInstance方法。
太陽照常升起,人生寂寞如雪。