前一章淺談了 app 的生命週期,這邊想要再深入的討論一些細節。
這次的 demo 看似跟上一篇很像,但實質上在生命週期的處理可是有許多的不同啊(汗)!上篇的旋轉螢幕可以知道,整個 Activity 會進到 onDestroy() 階段,但是這篇的 忍術 切頁之術! 可以看到,我只是透過 fragment manager 去做切換(replace)頁面的動作,只有 Fragment 會進入 onDestroy(),背後的 Activity 並沒有死去!
OS:真 4 麻煩 ...
沒錯!差別就在 Activity 是否進入 onDestroy
這很重要嗎?有一點,上一篇在臨走前,可以使用 onSaveInstanceState 去將資料保存好,以待下次回來時可以拿取,But,在這篇只有 fragment 會死去,並不能使用 onSaveInstanceState 去做保存,WHY ??
因為 fragment 的 onSaveInstanceState 是繼承自 Activity,當 Activity 並沒執行 onSaveInstanceState時,Fragment 也不能使用它 (參考連結)
那該怎辦呢?沒事沒事,只好自己實作一個用來儲存 Bundle 的 function 了,可以參考以下實作的 code
建立界面
照著做的話,現在在 nav_header_bar 應該會有兩個選項,這篇只是要按這兩個選項,達到切換 fragment 的效果,所以不用特別建立元件
臨走前,交代資料保存
現在我們都知道了,onSaveInstanceState 在這個情況無法使用 (上方有提到原因),所以必須另外實作一個 function 來幫我們存取 bundle
val outState = Bundle()
val FM_REPLACE_KEY = "replace"
fun saveBundle(){
outState.putString(FM_REPLACE_KEY, show_input?.text.toString())
}
甦醒!怎麼取之前保存好的值呢?
在我們的 onCreateView 裡面去接資料,如下
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if(outState.getString(FM_REPLACE_KEY) != null){
view.show_input.text = outState.getString(FM_REPLACE_KEY)
}
// blablabla
}
概念就是說,如果有找到這個 FM_REPLACE_KEY 值,表示先前有 fragment 存值了,那就把它取出來吧!而下面是一樣的意思,只是使用 kotlin 的 nullable 變數特性,將上面的程式碼給簡化
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
view.show_input.text = outState?.getString(FM_REPLACE_KEY)
// blablabla
}
不會進自定義的 saveBundle function?
沒錯,這個坑有點眼熟啊QQ這次不會進 saveBundle?其實後來才知道有進去,只是我誤會了。在點擊 nav_bar 的 item 去切換頁面的時候,沒有去檢查是否該 fragment 存在 fragment manager 裡面,導致即使 bundle 有存進去,但是每次按下 item 的時候,又去 new 一個新的實體出來,全新的實體,怎麼可能拿得到過去舊的資料呢!所以需要加入以下的判斷
when (item.itemId) {
R.id.nav_2 -> {
var tmpFragment: Fragment? = fm.findFragmentByTag("fragmentDemo")
if(tmpFragment == null)
tmpFragment = fragmentDemo()
fm.beginTransaction()
.setCustomAnimations(R.anim.fade_in, R.anim.fade_out)
.replace(R.id.loginFrame, tmpFragment, "fragmentDemo")
.addToBackStack(null)
.commit()
}
}
如果曾經存在過該 fragment,那把它叫出來就好,這樣我們就可以拿到他自己存好的 bundle; 否則,再去生一個新的 fragment。