iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 7
0
自我挑戰組

學習 Android Kotlin 隨筆系列 第 7

[ Day 7 ] 探討 Fragment 從年少輕狂,到老年退休生活!(二)忍術 切頁之術!

| 實作 code

  • 連結 | Android 專案
    • @commit: e60ee1e

| 生命週期

  • 連結 | 旋轉跳躍
  • 忍術 切頁之術!

| 生命週期概念(二)

前一章淺談了 app 的生命週期,這邊想要再深入的討論一些細節。

這次的 demo 看似跟上一篇很像,但實質上在生命週期的處理可是有許多的不同啊(汗)!上篇的旋轉螢幕可以知道,整個 Activity 會進到 onDestroy() 階段,但是這篇的 忍術 切頁之術! 可以看到,我只是透過 fragment manager 去做切換(replace)頁面的動作,只有 Fragment 會進入 onDestroy(),背後的 Activity 並沒有死去!

OS:真 4 麻煩 ...

沒錯!差別就在 Activity 是否進入 onDestroy
這很重要嗎?有一點,上一篇在臨走前,可以使用 onSaveInstanceState 去將資料保存好,以待下次回來時可以拿取,But,在這篇只有 fragment 會死去,並不能使用 onSaveInstanceState 去做保存,WHY ??
因為 fragmentonSaveInstanceState 是繼承自 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


上一篇
[ Day 6 ] 探討 Fragment 從年少輕狂,到老年退休生活!(一)旋轉跳躍,我跌一圈
下一篇
[ Day 8 ] 探討 Fragment 從年少輕狂,到老年退休生活!(三)樸實無華但有質感,開場動畫
系列文
學習 Android Kotlin 隨筆30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言