Fragment初始化方式
本文所有示例代码均使用以下依赖库当前的最新版本
implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.fragment:fragment:1.5.4"
implementation "androidx.fragment:fragment-ktx:1.5.4"
- 在布局文件中进行声明,利用标签定义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详细生命周期如下图,原图地址
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)
}
}
}