Android Code Club - Fragment
Android Fragment Kotlin Java
本週三去參加 Android Developer 開發讀書會 主辦的 Android Code Club
2020-08-19 Week 3 - Activity and Fragment
當天講者有提到說,如果 Fragment 被系統回收,系統再次生成這一個 fragment 只會用預設的 initial
這是一個很特別的情境,通常不會在其他語言也遇到,所以寫一篇文章來記錄整個狀況
=== 這是分隔線 ===
如我們剛才所說,系統只會用 default 的 initial func 去建立 fragment
可以在 Fragment 的 class Source code 裡面看到
It is strongly recommended to supply arguments with {@link #setArguments} * and later retrieved by the Fragment with {@link #getArguments}. These arguments * are automatically saved and restored alongside the Fragment.
  /**
    * Constructor used by the default {@link FragmentFactory}. You must
    * {@link FragmentManager#setFragmentFactory(FragmentFactory) set a custom FragmentFactory}
    * if you want to use a non-default constructor to ensure that your constructor
    * is called when the fragment is re-instantiated.
    *
    * <p>It is strongly recommended to supply arguments with {@link #setArguments}
    * and later retrieved by the Fragment with {@link #getArguments}. These arguments
    * are automatically saved and restored alongside the Fragment.
    *
    * <p>Applications should generally not implement a constructor. Prefer
    * {@link #onAttach(Context)} instead. It is the first place application code can run where
    * the fragment is ready to be used - the point where the fragment is actually associated with
    * its context. Some applications may also want to implement {@link #onInflate} to retrieve
    * attributes from a layout resource, although note this happens when the fragment is attached.
    */
  public Fragment() {
      initLifecycle();
  }
既然官方強烈的建議我們要這樣做,那就照著做比較沒問題
通常我們為了方便,當然會建立 BaseFragment 做好一些事,方便使用
也會使用 kotlin 的特性,保證某些變數必然要被傳進來
like this
abstract class TestBaseFragment(@LayoutRes private val layout: Int) : Fragment() {
    // Do Something
}
class TestSubFragment private constructor(private val id: String) : TestBaseFragment(
    R.layout.xxxx
) {
    companion object {
        fun newInstance(id: String) = TestSubFragment(id = id)
    }
}
所以,這樣的寫法,在 Fragment 被系統回收後再生,就會因為 id 沒有值,出現非我們期望的結果
甚至是 Crash
為了避免出現非我們預期的結果,或者是 Crash,我們就需要換種寫法
class TestSubFragment private constructor() : TestBaseFragment(
    R.layout.xxxx
) {
    private val id: String = arguments?.getString("id", "") ?: ""
    companion object {
        fun newInstance(id: String): TestSubFragment {
            val f = TestSubFragment()
            val args = Bundle()
            args.putString("id", id)
            f.arguments = args
            return f
        }
    }
}
這樣就可以避開這一個奇怪的坑(Android 真是一個神奇的平台)
打完收工!