Fragment生命周期、使用注意事项

185 阅读2分钟

Fragment初始化方式

本文所有示例代码均使用以下依赖库当前的最新版本

implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.fragment:fragment:1.5.4"
implementation "androidx.fragment:fragment-ktx:1.5.4"
  1. 在布局文件中进行声明,利用标签定义Fragment有三种方法为Fragment提供ID:
    android:id:唯一的id
    android:tag:唯一的字符串
    如果上面两个都没提供,系统使用容器view的ID

2、在代码中进行初始化,通过获取FragmentManager开启事务transaction,可进行add、replace、remove、hide、show、attach、dettach等相关操作

Fragment生命周期

class CustomViewActivity:AppCompatActivity() {

    companion object{
        private const val TAG = "CustomViewActivity"
    }

    private val viewModel by viewModels<CustomViewModel>()

    override fun onStart() {
        super.onStart()
        Log.d("CustomViewActivity", "onStart")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.custom_activity_layout)
        Log.d("CustomViewActivity", "onCreate")

        val fragment1 = FirstFragment().apply {
            arguments = Bundle().apply {
            putString("key", "key1")
        }
    }
        val fragment2 = SecondFragment()

        supportFragmentManager.commit {
            add(R.id.container, fragment1)
//          add(R.id.container, fragment2)
//          replace(R.id.container, fragment2)
        }
        findViewById<Button>(R.id.add).setOnClickListener {
            viewModel.changeValue()
            supportFragmentManager.beginTransaction().remove(fragment1).commit()
//          supportFragmentManager.beginTransaction().hide(fragment2).commit()
        }
    }
}

class FirstFragment:Fragment() {

    companion object{
        private const val TAG = "FirstFragment"
    }
    
    //只有在布局文件中声明才会执行onInflate()方法
    override fun onInflate(context: Context, attrs: AttributeSet, savedInstanceState: Bundle?) {
        super.onInflate(context, attrs, savedInstanceState)
        Log.d(TAG, "onInflate")
    }

    /**
    * 当Activity和Fragment交互的时候,我们可以在Activity中通过Fragment.setArguments()的方法Fragment提供数据,
    * 然后再Fragment的onAttach()方法中getArguments()获得一个Bundle对象
    **/
    override fun onAttach(context: Context) {
        super.onAttach(context)
        Log.d(TAG, "onAttach")
        arguments?.apply {
            val value = getString("key")
            Log.d(TAG, "onAttach  value:$value")
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate")
    }
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        Log.d(TAG, "onCreateView")
        return inflater.inflate(R.layout.custom_fragment, container, false)
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Log.d(TAG, "onViewCreated")
    }
    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart")
    }
    override fun onResume() {
        super.onResume()
        Log.d(TAG, "onResume")
    }
    override fun onPause() {
        super.onPause()
        Log.d(TAG, "onPause")
    }
    override fun onStop() {
        super.onStop()
        Log.d(TAG, "onStop")
    }
    override fun onDestroyView() {
        super.onDestroyView()
        Log.d(TAG, "onDestroyView")
    }
    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy")
    }
    override fun onDetach() {
        super.onDetach()
        Log.d(TAG, "onDetach")
    }
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
    }
}

场景1:通过add()添加Fragment后点击按钮执行remove()操作,Fragment执行整个完整生命周期回调

D/CustomViewActivity: onCreate
D/FirstFragment: onAttach
D/FirstFragment: onCreate
D/FirstFragment: onCreateView
D/FirstFragment: onViewCreated
D/FirstFragment: onStart
D/CustomViewActivity: onStart
D/CustomViewActivity: onResume
D/FirstFragment: onResume
//执行remove操作后
D/FirstFragment: onPause
D/FirstFragment: onStop
D/FirstFragment: onDestroy
D/FirstFragment: onDestroy
D/FirstFragment: onDetach

场景2:通过add()添加Fragment后点击按钮执行hide()操作,Fragment执行OnResume前生命周期回调,onPause()后台生命周期并未执行

D/CustomViewActivity: onCreate
D/FirstFragment: onAttach
D/FirstFragment: onCreate
D/FirstFragment: onCreateView
D/FirstFragment: onViewCreated
D/FirstFragment: onStart
D/CustomViewActivity: onStart
D/CustomViewActivity: onResume
D/FirstFragment: onResume
//执行hide操作后

场景3:连续两次add()同一个Fragment,应用崩溃,提示原因不能同时添加同一个Fragment

 java.lang.IllegalStateException: Fragment already added: FirstFragment{4c8b9eb}

场景4:执行一次add()后再执行replace(),,Fragment执行OnResume前生命周期回调,onPause()后台生命周期并未执行

D/CustomViewActivity: onCreate
D/FirstFragment: onAttach
D/FirstFragment: onCreate
D/FirstFragment: onCreateView
D/FirstFragment: onViewCreated
D/FirstFragment: onStart
D/CustomViewActivity: onStart
D/CustomViewActivity: onResume
D/FirstFragment: onResume

场景5:连续add()两个Fragment,FristFragment、SecondFragment,两个Fragment都只执行OnResume前生命周期回调

D/CustomViewActivity: onCreate
D/FirstFragment: onAttach
D/FirstFragment: onCreate
D/FirstFragment: onCreateView
D/FirstFragment: onViewCreated
D/SecondFragment: onAttach
D/SecondFragment: onCreate
D/SecondFragment: onCreateView
D/SecondFragment: onViewCreated
D/FirstFragment: onStart
D/SecondFragment: onStart
D/CustomViewActivity: onStart
D/CustomViewActivity: onResume
D/FirstFragment: onResume
D/SecondFragment: onResume

场景6:先add() FristFragment、再执行replace() SecondFragment,FristFragment执行完整生命周期,SecondFragment执行OnResume前生命周期回调
前提条件:add、replace后都需执行commit操作,若在add、replace后执行commit操作,只会回调SecondFragment相关生命周期回调

D/CustomViewActivity: onCreate
D/FirstFragment: onAttach
D/FirstFragment: onCreate
D/FirstFragment: onCreateView
D/FirstFragment: onViewCreated
D/SecondFragment: onAttach
D/SecondFragment: onCreate
D/SecondFragment: onCreateView
D/SecondFragment: onViewCreated
D/FirstFragment: onDestroyView
D/FirstFragment: onDestroy
D/FirstFragment: onDetach
D/SecondFragment: onStart
D/CustomViewActivity: onStart
D/CustomViewActivity: onResume
D/SecondFragment: onResume

Fragment详细生命周期如下图,原图地址 3336483-a5aee489135f5d17.jpg

Fragment与Activity通信

官方推荐最新方案,通过ViewModel实现一个Activity多个Fragment执行通信,可以在FristFragment中初始化宿主Activity作用域的ViewModel,但是无法通过SavedStateHandle获取Arguments

class FirstFragmentViewModel(savedStateHandle: SavedStateHandle?):ViewModel() {
    companion object{
        private const val TAG = "FirstFragmentViewModel"
    }

    init {
        Log.d(TAG, "init")
        savedStateHandle?.apply {
            val value = get<String>("key")
            Log.d(TAG, "init value:$value")
        }
    }

    fun getBundle(){
        Log.d(TAG, "getBundle")
    }
}
    
/**
* 获取宿主Activity共享的ViewModel,实现多个Fragment共享数据操作
**/    
private val activityViewModel by activityViewModels<FirstFragmentViewModel>()
    D/FirstFragmentViewModel: init
    D/FirstFragmentViewModel: init value:null

/**
* 可以用于初始化Fragment时通知setArgument()进行传值操作
**/
private val viewModel by viewModels<FirstFragmentViewModel>()
    D/FirstFragmentViewModel: init
    D/FirstFragmentViewModel: init value:key1

Fragment避坑指南

Fragment全解析系列(一):那些年踩过的坑 - 简书 (jianshu.com)

Fragment监听返回按键

class BackPressFragment : AbsBaseFragment() {
    private var extime: Long = 0
    private val cb by lazy {
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (System.currentTimeMillis() - extime > 1000) {
                    Toast.makeText(context, "Click again to return", Toast.LENGTH_SHORT).show()
                    extime = System.currentTimeMillis()
                } else {
                    navigator.pop()
                }
            }
        }
    }
...
    override fun onAttach(context: Context) {
        super.onAttach(context)
        Handler().post {
            requireActivity().onBackPressedDispatcher.addCallback(this, cb)
        }
    }
}

第三方Fragment管理插件

Fragivity:像使用Activity一样使用Fragment - 掘金 (juejin.cn)

文章参考:
一文读懂 Fragment 的方方面面 - 掘金 (juejin.cn)