前一章淺談了 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
。