形形色色的Fragment生命周期
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
Fragment
生命周期在不同的组件下使用具有不同的生命周期,如Activity
中,viewpager2
或viewpager
.
相关类声明
class FragmentOne(val logTag: String) : Fragment() {
override fun onAttach(context: Context) {
super.onAttach(context)
Log.e(logTag, "onAttach")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.e(logTag, "onCreate")
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
Log.e(logTag, "onCreateView")
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Log.e(logTag, "onActivityCreated")
}
override fun onStart() {
super.onStart()
Log.e(logTag, "onStart ")
}
override fun onResume() {
super.onResume()
Log.e(logTag, "onResume")
}
override fun onPause() {
super.onPause()
Log.e(logTag, "onPause")
}
override fun onStop() {
super.onStop()
Log.e(logTag, "onStop")
}
override fun onDestroyView() {
super.onDestroyView()
Log.e(logTag, "onDestroyView")
}
override fun onDestroy() {
Log.e(logTag, "onDestroy")
super.onDestroy()
}
override fun onDetach() {
super.onDetach()
Log.e(logTag, "onDetach")
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
Log.e(logTag, "onHiddenChanged ${hidden}")
}
}
class MainActivity : AppCompatActivity() {
val logTag = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.e(logTag, "onCreate")
}
override fun onRestart() {
super.onRestart()
Log.e(logTag, "onRestart")
}
override fun onStart() {
super.onStart()
Log.e(logTag, "onStart")
}
override fun onResume() {
super.onResume()
Log.e(logTag, "onResume")
}
override fun onPause() {
super.onPause()
Log.e(logTag, "onPause")
}
override fun onStop() {
super.onStop()
Log.e(logTag, "onStop")
}
override fun onDestroy() {
super.onDestroy()
Log.e(logTag, "onDestroy")
}
}
一、Activity下的各类生命周期
一、单纯FragmentManager添加或隐藏
class MainActivity : AppCompatActivity() {
//.......
//....省略生命周期打印代码
//.......
val fragmentOne = FragmentOne("FragmentOne")
fun submitClick(view: View) {
Log.e(logTag, "提交FragmentOne到事物")
supportFragmentManager.beginTransaction()
.add(R.id.fl_container, fragmentOne)
.commitNowAllowingStateLoss()
}
fun hideClick(view: View) {
Log.e(logTag, "隐藏FragmentOne到事物")
supportFragmentManager.beginTransaction()
.hide( fragmentOne)
.commitNowAllowingStateLoss()
}
}
(1)调用submitClick
函数添加fragment
正常生命周期如下:
这个生命周期是基础业务知识所以不做例子讲解
(2)调用hideClick
函数隐藏fragment
不影响生命周期,但是会回调onHiddenChanged
函数,传入参数为true
.
简单来说隐藏fragment操作后回调onHiddenChanged
,但是不影响跟随Activity生命周期.比如调用隐藏函数后,按下Home键返回主页,在返回应用.
二、FragmentManager回退栈
提交代码
fun submitClick(view: View) {
Log.e(logTag, "提交FragmentOne-one")
supportFragmentManager.beginTransaction()
.addToBackStack(null)
.add(R.id.fl_container, fragmentOne)
.commit()
thread {
//之所以加上休眠时间间隔 为了区区分打印两个生命周期方便
TimeUnit.SECONDS.sleep(1)
runOnUiThread {
Log.e(logTag, "提交FragmentOne-two")
supportFragmentManager.beginTransaction()
.addToBackStack(null)
.add(R.id.fl_container, fragmenttwo)
.commit()
}
}
}
日志输出:
MainActivity: 提交FragmentOne-one
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
MainActivity: 提交FragmentOne-two
FragmentOne-two: onAttach
FragmentOne-two: onCreate
FragmentOne-two: onCreateView
FragmentOne-two: onActivityCreated
FragmentOne-two: onStart
FragmentOne-two: onResume
生命周期没有太多特殊地方.
弹出:
fun hideClick(view: View) {
Log.e(logTag, "弹出FragmentOne-two")
supportFragmentManager.popBackStack()
thread {
//之所以加上休眠时间间隔 为了区区分打印两个生命周期方便
TimeUnit.SECONDS.sleep(1)
runOnUiThread {
Log.e(logTag, "弹出FragmentOne-one")
supportFragmentManager.popBackStack()
}
}
}
输出:
MainActivity: 弹出FragmentOne-two
FragmentOne-two: onPause
FragmentOne-two: onStop
FragmentOne-two: onDestroyView
FragmentOne-two: onDestroy
FragmentOne-two: onDetach
MainActivity: 弹出FragmentOne-one
FragmentOne-one: onPause
FragmentOne-one: onStop
FragmentOne-one: onDestroyView
FragmentOne-one: onDestroy
FragmentOne-one: onDetach
三、FragmentManager 替换(replace)
fun submitClick(view: View) {
Log.e(logTag, "提交FragmentOne-one")
supportFragmentManager.beginTransaction()
.replace(R.id.fl_container, fragmentOne)
.commit()
thread {
//之所以加上休眠时间间隔 为了区区分打印两个生命周期方便
TimeUnit.SECONDS.sleep(1)
runOnUiThread {
Log.e(logTag, "提交FragmentOne-two")
supportFragmentManager.beginTransaction()
.replace(R.id.fl_container, fragmenttwo)
.commit()
}
}
}
输出:
MainActivity: 提交FragmentOne-one
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
MainActivity: 提交FragmentOne-two
FragmentOne-two: onAttach
FragmentOne-two: onCreate
FragmentOne-one: onPause
FragmentOne-one: onStop
FragmentOne-one: onDestroyView
FragmentOne-one: onDestroy
FragmentOne-one: onDetach
FragmentOne-two: onCreateView
FragmentOne-two: onActivityCreated
FragmentOne-two: onStart
FragmentOne-two: onResume
如果配合回退栈情况:
fun submitClick(view: View) {
Log.e(logTag, "提交FragmentOne-one")
supportFragmentManager.beginTransaction()
.addToBackStack(null)
.replace(R.id.fl_container, fragmentOne)
.commit()
thread {
//之所以加上休眠时间间隔 为了区区分打印两个生命周期方便
TimeUnit.SECONDS.sleep(1)
runOnUiThread {
Log.e(logTag, "提交FragmentOne-two")
supportFragmentManager.beginTransaction()
.addToBackStack(null)
.replace(R.id.fl_container, fragmenttwo)
.commit()
}
}
}
输出:
MainActivity: 提交FragmentOne-one
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
MainActivity: 提交FragmentOne-two
FragmentOne-two: onAttach
FragmentOne-two: onCreate
FragmentOne-one: onPause
FragmentOne-one: onStop
FragmentOne-one: onDestroyView
FragmentOne-two: onCreateView
FragmentOne-two: onActivityCreated
FragmentOne-two: onStart
FragmentOne-two: onResume
点击回退后的弹出信息:
FragmentOne-two: onPause
FragmentOne-two: onStop
FragmentOne-two: onDestroyView
FragmentOne-two: onDestroy
FragmentOne-two: onDetach
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
总结:
添加回退栈后生命周期如果被replace 那么生命周期会结束在onDestroyView
,返回后重建视图从onCreateView
开始
四、FragmentManager 分离/附加(detach,attach)
fun submitClick(view: View) {
Log.e(logTag, "提交FragmentOne-one")
supportFragmentManager.beginTransaction()
.add(R.id.fl_container, fragmentOne)
.commit()
}
fun hideClick(view: View) {
Log.e(logTag, "-----------------------" )
Log.e(logTag, "fragmentOne detach" )
supportFragmentManager.beginTransaction()
.detach( fragmentOne)
.commitNowAllowingStateLoss()
Log.e(logTag, "-----------------------" )
Log.e(logTag, "fragmentOne attch" )
supportFragmentManager.beginTransaction()
.attach( fragmentOne)
.commitNowAllowingStateLoss()
Log.e(logTag, "-----------------------" )
}
输出:
MainActivity: 提交FragmentOne-one
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
MainActivity: -----------------------
MainActivity: fragmentOne detach
FragmentOne-one: onPause
FragmentOne-one: onStop
FragmentOne-one: onDestroyView
MainActivity: -----------------------
MainActivity: fragmentOne attch
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
MainActivity: -----------------------
tip:如果fragment
已经被attach/detach
那么再次调用对应的supportFragmentManager
的attach/detach
将不会有任何反应.
五、FragmentManager setMaxLifecycle
setMaxLifecycle
我也是在近期阅读源码时才发现,此函数用于设置某个fragment
在FragmentManager
最大的生命周期.
fun submitClick(view: View) {
Log.e(logTag, "提交FragmentOne-one")
supportFragmentManager.beginTransaction()
.add(R.id.fl_container, fragmentOne)
.setMaxLifecycle(fragmentOne,Lifecycle.State.CREATED)
.commit()
}
MainActivity: 提交FragmentOne-one
FragmentOne-one: onAttach
FragmentOne-one: onCreate
MainActivity: onPause
MainActivity: onStop
MainActivity: onRestart
MainActivity: onStart
MainActivity: onResume
可见设置最大生命周期后哪怕Activity
生命周期变化fragment
也必须遵循setMaxLifecycle
.
二、ViewPager
下的生命周期
首先需要明白viewpager2
两种适配类别
adapter
两种类型
(1)FragmentStatePagerAdapter
(2)FragmentPagerAdapter
两个适配最大的区别在于函数destroyItem
中如何处理销毁fragment
FragmentStatePagerAdapter
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
//...
Fragment fragment = (Fragment) object;
mCurTransaction.remove(fragment);
//...
}
FragmentPagerAdapter
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment) object;
mCurTransaction.detach(fragment);
}
可以简单理解FragmentStatePagerAdapter
会完全移除fragment,FragmentPagerAdapter
仅会detach
,如果对于内存比较紧张且不考虑再次使用可以使用FragmentStatePagerAdapter
.
本文仅探究FragmentPagerAdapter
(知道这个完全意会FragmentStatePagerAdapter
)
构造函数
FragmentStatePagerAdapter(@NonNull FragmentManager fm,
@Behavior int behavior)
我们看下第二参数参数枚举:
@Retention(RetentionPolicy.SOURCE)
@IntDef({BEHAVIOR_SET_USER_VISIBLE_HINT, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT})
private @interface Behavior { }
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
:
被加载的且对用户可见的fragment
同步activity
生命周期到onResume
函数,其余对用户不可见的fragment
不会回调到onResume
.
BEHAVIOR_SET_USER_VISIBLE_HINT
:
所有已经被viewpager加载且未移除的fragment
和Activity
同步生命周期,但是会回调setUserVisibleHint
判断是否对用户可见,或者获取userVisibleHint
属性进行判断.这选项已弃用.注意onHiddenChanged
并不回调
BEHAVIOR_SET_USER_VISIBLE_HINT
举例子说明:
class MyFragmentAdapter constructor(
fm: FragmentManager,
behavior: Int
) : FragmentPagerAdapter(fm, behavior) {
//) : FragmentPagerAdapter(fm, behavior) {
val fragmentList =
listOf<FragmentOne>(
FragmentOne("FragmentOne-one"),
FragmentOne("FragmentOne-two"),
FragmentOne("FragmentOne-three"),
FragmentOne("FragmentOne-four"),
FragmentOne("FragmentOne-five"),
)
override fun getCount(): Int {
return fragmentList.size
}
override fun getItem(position: Int): Fragment {
return fragmentList[position]
}
}
//vp是viewpager对象
vp = findViewById(R.id.viewpager)
//初始化
val myFragmentAdapter = MyFragmentAdapter(
supportFragmentManager,
FragmentPagerAdapter.BEHAVIOR_SET_USER_VISIBLE_HINT
)
vp.adapter = myFragmentAdapter
vp.offscreenPageLimit = 1
myFragmentAdapter.notifyDataSetChanged()
vp显示第一个fragment
(FragmentOne-one
)
MainActivity: onCreate
MainActivity: onStart
MainActivity: onResume
FragmentOne-one: setUserVisibleHint false
FragmentOne-two: setUserVisibleHint false
FragmentOne-one: setUserVisibleHint true
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-two: onAttach
FragmentOne-two: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
FragmentOne-two: onCreateView
FragmentOne-two: onActivityCreated
FragmentOne-two: onStart
FragmentOne-two: onResume
注意点:
(1)FragmentOne-two
被初始化是因为我们设offscreenPageLimit
为1,所以预加载显示fragment
两侧各1个fragment
.
(2)FragmentOne-two
setUserVisibleHint 被回调 且传入参数为true 标识当前不可以对用可见
(3)BEHAVIOR_SET_USER_VISIBLE_HINT
会让所有被加载的fragment
同步Activity
生命周期
vp滑动到第二个fragment
(FragmentOne-two
)
FragmentOne-three: setUserVisibleHint false
FragmentOne-one: setUserVisibleHint false
FragmentOne-two: setUserVisibleHint true
FragmentOne-three: onAttach
FragmentOne-three: onCreate
FragmentOne-three: onCreateView
FragmentOne-three: onActivityCreated
FragmentOne-three: onStart
FragmentOne-three: onResume
在第二个fragment
(FragmentOne-two
)后 此时按下home
键 (可见被加载的所有fragment同步生命周期)
FragmentOne-one: onPause
FragmentOne-two: onPause
FragmentOne-three: onPause
MainActivity: onPause
FragmentOne-one: onStop
FragmentOne-two: onStop
FragmentOne-three: onStop
MainActivity: onStop
滑动到第三个fragment(FragmentOne-three
),第一个fragment(FragmentOne-one
)被销毁.(FragmentPagerAdapter销毁操作只执行detach
)
FragmentOne-four: setUserVisibleHint false
FragmentOne-two: setUserVisibleHint false
FragmentOne-three: setUserVisibleHint true
FragmentOne-four: onAttach
FragmentOne-four: onCreate
FragmentOne-one: onPause
FragmentOne-one: onStop
FragmentOne-one: onDestroyView
FragmentOne-four: onCreateView
FragmentOne-four: onActivityCreated
FragmentOne-four: onStart
FragmentOne-four: onResume
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
被加载的且对用户可见的fragment
同步activity
生命周期到onResume
函数,其余对用户不可见的函数不会回调到onResume
.
比如,当前显示第一个fragment,已经预加载第二个fragment,此时第二个fragment生命周期只会执行到onpuase
.而第一个fragment会执行到onresume
.假设用户按下home按键返回主页,第一个fragment会跟随Activity执行onpuase
onstop
.第二个fragment不会有任何回调.
vp = findViewById(R.id.viewpager)
//初始化
val myFragmentAdapter = MyFragmentAdapter(
supportFragmentManager,
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
)
vp.adapter = myFragmentAdapter
vp.offscreenPageLimit = 1
myFragmentAdapter.notifyDataSetChanged()
class MyFragmentAdapter constructor(
fm: FragmentManager,
behavior: Int
) : FragmentPagerAdapter(fm, behavior) {
//) : FragmentPagerAdapter(fm, behavior) {
val fragmentList =
listOf<FragmentOne>(
FragmentOne("FragmentOne-one"),
FragmentOne("FragmentOne-two"),
FragmentOne("FragmentOne-three"),
FragmentOne("FragmentOne-four"),
FragmentOne("FragmentOne-five"),
)
override fun getCount(): Int {
return fragmentList.size
}
override fun getItem(position: Int): Fragment {
return fragmentList[position]
}
}
显示第一个fragment(FragmentOne-one
)
输出:
MainActivity: onCreate
MainActivity: onStart
MainActivity: onResume
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-two: onAttach
FragmentOne-two: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-two: onCreateView
FragmentOne-two: onActivityCreated
FragmentOne-two: onStart
FragmentOne-one: onResume
可以看到第二个fragment(FragmentOne-two
)只能处于onstart状态,并没有到onresume
.
此时我们按下home
按键
FragmentOne-one: onPause
MainActivity: onPause
FragmentOne-one: onStop
FragmentOne-two: onStop
MainActivity: onStop
此时在从后台返回返回到应用
MainActivity: onRestart
FragmentOne-one: onStart
FragmentOne-two: onStart
MainActivity: onStart
MainActivity: onResume
FragmentOne-one: onResume
vp滑动到第二个fragment(FragmentOne-two
)
FragmentOne-three: onAttach
FragmentOne-three: onCreate
FragmentOne-three: onCreateView
FragmentOne-three: onActivityCreated
FragmentOne-three: onStart
FragmentOne-one: onPause
总结:
(1) BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
只有对用户显示的fragment才能回调onresume
函数
(2) 被滑出不可见且未被销毁会走到onpuase
(3) Activity
返回主页执行到后台或者销毁,所有被加载的fragment
也会同步
(4) Activity
从后台恢复到前台,对用户不显示的fragment
会走到onstart
函数,对用户可见的fragment
会走到onresume
函数
(5) …
三、ViewPager2
下的生命周期
ViewPager2
基于RecycleView
实现,所以三级缓存机制会影响到fragment的销毁(三级缓存默认为5个).
如果offscreenPageLimit
小于5,那么vp2滑动到第五个fragment
将会对第一个fragment
执行remove
操作.
所有被加载的fragment
生命周期同viewpager
的BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
一样,除了被销毁机制之外.
vp2 = findViewById(R.id.viewpager2)
//初始化
val myFragmentAdapter = MyFragmentAdapter(supportFragmentManager, lifecycle)
vp2.adapter = myFragmentAdapter
vp2.offscreenPageLimit = 1
myFragmentAdapter.notifyDataSetChanged()
class MyFragmentAdapter constructor(
fm: FragmentManager,
lifecycle: Lifecycle
) : androidx.viewpager2.adapter.FragmentStateAdapter(fm, lifecycle) {
val fragmentList =
listOf(
FragmentOne("FragmentOne-one"),
FragmentOne("FragmentOne-two"),
FragmentOne("FragmentOne-three"),
FragmentOne("FragmentOne-four"),
FragmentOne("FragmentOne-five"),
FragmentOne("FragmentOne-six"),
FragmentOne("FragmentOne-seven"),
)
override fun getItemCount(): Int {
return fragmentList.size
}
override fun createFragment(position: Int): Fragment {
return fragmentList[position]
}
}
显示第一个fragment时
MainActivity: onCreate
MainActivity: onStart
MainActivity: onResume
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
FragmentOne-two: onAttach
FragmentOne-two: onCreate
FragmentOne-two: onCreateView
FragmentOne-two: onActivityCreated
FragmentOne-two: onStart
按下home
按键
FragmentOne-one: onPause
MainActivity: onPause
FragmentOne-one: onStop
FragmentOne-two: onStop
MainActivity: onStop
从后台返回到前台
MainActivity: onRestart
FragmentOne-one: onStart
FragmentOne-two: onStart
MainActivity: onStart
MainActivity: onResume
FragmentOne-one: onResume
其它类似BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
所以不再举例.
Viewpager2销毁逻辑举例:
还是上面的例子我们直接滑动第五个Fragment(FragmentOne-five
).
/*显示第一个Fragment*/
MainActivity: onCreate
MainActivity: onStart
MainActivity: onResume
FragmentOne-one: onAttach
FragmentOne-one: onCreate
FragmentOne-one: onCreateView
FragmentOne-one: onActivityCreated
FragmentOne-one: onStart
FragmentOne-one: onResume
FragmentOne-two: onAttach
FragmentOne-two: onCreate
FragmentOne-two: onCreateView
FragmentOne-two: onActivityCreated
FragmentOne-two: onStart
/*显示第二个Fragment*/
FragmentOne-three: onAttach
FragmentOne-three: onCreate
FragmentOne-three: onCreateView
FragmentOne-three: onActivityCreated
FragmentOne-three: onStart
FragmentOne-one: onPause
FragmentOne-two: onResume
/*显示第三个Fragment*/
FragmentOne-four: onAttach
FragmentOne-four: onCreate
FragmentOne-four: onCreateView
FragmentOne-four: onActivityCreated
FragmentOne-four: onStart
FragmentOne-two: onPause
FragmentOne-three: onResume
/*显示第四个Fragment*/
FragmentOne-five: onAttach
FragmentOne-five: onCreate
FragmentOne-five: onCreateView
FragmentOne-five: onActivityCreated
FragmentOne-five: onStart
FragmentOne-three: onPause
FragmentOne-four: onResume
/*显示第五个Fragment*/
FragmentOne-six: onAttach
FragmentOne-six: onCreate
FragmentOne-six: onCreateView
FragmentOne-six: onActivityCreated
FragmentOne-six: onStart
FragmentOne-one: onStop
FragmentOne-one: onDestroyView
FragmentOne-one: onDestroy
FragmentOne-one: onDetach
FragmentOne-four: onPause
FragmentOne-five: onResume
可以看到滑动到第五个时FragmentOne-one
完全被移除销毁.如果你的业务不需要销毁只需要扩大offscreenPageLimit
大小
本文地址:https://blog.csdn.net/qfanmingyiq/article/details/108495723