[关闭]
@martin0207 2018-12-12T05:42:10.000000Z 字数 6472 阅读 1107

实现Fragment懒加载(二)—— 实现ILazyInitFragment

android


镇楼

GIF1.gif

前言

懒加载的作用上一篇中已经叙述过了,这篇拓展上一篇中:之所以费劲提取出来,是因为考虑到,已经成型的项目,替换BaseFragment类很费劲,我希望能够让Fragment只实现一个接口就可以实现这个功能
牛皮吹出去了,总不能放着不管。这里仅需要:

  1. Fragment仅实现ILazyInitFragment接口。
  2. 不破坏原代码的前提下,添加10行代码。
  3. 所属Activity中添加3行代码。

即可实现懒加载功能。

重点

想要实现前面说的,前提是需要知道:Activity可以通过supperFragmentManager注册监听所拥有的Fragment的生命周期

  1. /*
  2. 注册Fragment生命周期监听
  3. */
  4. supportFragmentManager.registerFragmentLifecycleCallbacks(
  5. //传入我们实现的类
  6. FragmentLifecycleForLazyInitImpl(),
  7. /*
  8. 是否递归Fragment中的Fragment
  9. 我们这里不做处理了
  10. */
  11. false
  12. )

分析

说些我们知道的

  1. 关于setUserVisibleHint的分析可以看上篇。
  2. 实现接口相较于继承父类,优点在于可以实现多个接口,不破坏原有代码的继承关系
    • 不能创建非静态全局变量
      • 我们需要将全局变量提取出来,创建LazyInitModel
  3. Activity可以通过supperFragmentManager注册监听所拥有的Fragment的生命周期
    • 我们就可以将上一篇中,LazyInitFragment在生命周期中的操作拿出来,放在监听类中。
  4. setUserVisibleHint调用时也需要判断是否需要调用懒加载方法
    • 3中没有关联监听到setUserVisibleHint的方法
      • 该方法需要实现接口的Fragment主动实现并调用了

分析了这些条件,相信会有一些模糊的框架出来了,下面开始冻手

实现

1. LazyInitModel

咱们先看看之前创建的全局变量

全局变量分析

嗯~图片说的很对,咱就不多说了。
除了变量,我们需要设置修改是否对用户可见当前生命周期的方法,并在方法调用时判断是否调用需要懒加载。

来来来,上代码:

  1. open class LazyInitModel(val mLazyInitFragment: ILazyInitFragment) {
  2. /**
  3. * fragment的当前状态
  4. * 用来控制lazyInit的调用
  5. */
  6. var mCurrentState = ILazyInitFragment.ON_ATTACH
  7. /**
  8. * 调用lazyInit的状态判定
  9. * 即mCurrentState>=getLazyInitState时,调用
  10. * 这里设置为方法,是为了方便用户使用的时候,能够自定义该方法
  11. */
  12. open fun getLazyInitState() = ILazyInitFragment.ON_ACTIVITY_CREATED
  13. /**
  14. * 是否已经初始化
  15. */
  16. var mInitialized = false
  17. /**
  18. * 用户是否可见
  19. */
  20. var mIsVisibleToUser = false
  21. /**
  22. * 设置当前是否对用户可见
  23. */
  24. fun setUserVisibleHint(isVisibleToUser: Boolean) {
  25. mIsVisibleToUser = isVisibleToUser
  26. doLazyInit()
  27. }
  28. /**
  29. * 设置当前生命周期
  30. */
  31. fun setCurrentState(state: Int) {
  32. mCurrentState = state
  33. doLazyInit()
  34. }
  35. private fun doLazyInit() {
  36. /*
  37. 若达到我们设置的状态条件,则调用方法
  38. 未初始化 且
  39. 用户可见 且
  40. 当前状态>= 懒加载触发状态
  41. */
  42. if (!mInitialized && mIsVisibleToUser && mCurrentState >= getLazyInitState()) {
  43. mLazyInitFragment.lazyInit()
  44. mInitialized = true
  45. }
  46. }
  47. }

2. 接口

model有了,我们需要通过接口获取该对象,所以需要在接口中添加获取model对象的方法:

  1. interface ILazyInitFragment {
  2. /**
  3. * fragment的状态
  4. * 延迟初始化一般都在这几种状态下(ATTACH除外)
  5. * 所以只添加了这些状态
  6. */
  7. companion object {
  8. /**
  9. * fragment依附于Activity(默认状态)
  10. * 一般处于该状态下,不做任何操作
  11. */
  12. const val ON_ATTACH = 0
  13. const val ON_CREATED = 1
  14. const val ON_CREATED_VIEW = 2
  15. /**
  16. * 推荐在下面两个状态下初始化
  17. */
  18. const val ON_ACTIVITY_CREATED = 3
  19. const val ON_RESUME = 4
  20. }
  21. /**
  22. * 延迟初始化
  23. */
  24. fun lazyInit() {}
  25. /**
  26. * 获取懒加载model
  27. * 继承LazyInitFragment的不需要管该方法
  28. * 是为了只实现接口功能而设立
  29. */
  30. fun getLazyInitModel(): LazyInitModel? = null
  31. }

这里将getLazyInitModel设置可空并且设置默认值,是为了与上一篇的代码不冲突。

3. Fragment生命周期监听类

Fragment生命周期监听类需要继承FragmentManager.FragmentLifecycleCallbacks,然后实现里面的各生命周期方法,现在我们只需要实现
onFragmentResumed以及onFragmentViewDestroyed方法即可

  1. /**
  2. * Activity可以通过supportFragmentManager来注册监听Fragment的生命周期
  3. * 因为只有生命周期的监听,而没有`setUserVisibleHint`方法监听
  4. * 所以需要在Fragment中手动调用设置方法
  5. */
  6. class FragmentLifecycleForLazyInitImpl : FragmentManager.FragmentLifecycleCallbacks() {
  7. override fun onFragmentAttached(fm: FragmentManager, f: Fragment, context: Context) {
  8. super.onFragmentAttached(fm, f, context)
  9. setLifecycleState(f, ILazyInitFragment.ON_ATTACH)
  10. }
  11. override fun onFragmentCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
  12. super.onFragmentCreated(fm, f, savedInstanceState)
  13. setLifecycleState(f, ILazyInitFragment.ON_CREATED)
  14. }
  15. override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) {
  16. super.onFragmentViewCreated(fm, f, v, savedInstanceState)
  17. setLifecycleState(f, ILazyInitFragment.ON_CREATED_VIEW)
  18. }
  19. override fun onFragmentActivityCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
  20. super.onFragmentActivityCreated(fm, f, savedInstanceState)
  21. setLifecycleState(f, ILazyInitFragment.ON_ACTIVITY_CREATED)
  22. }
  23. override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
  24. super.onFragmentResumed(fm, f)
  25. setLifecycleState(f,ILazyInitFragment.ON_RESUME)
  26. }
  27. override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
  28. super.onFragmentViewDestroyed(fm, f)
  29. /**
  30. * 这里是个小坑
  31. * ViewPager的规则,默认会销毁当前Fragment及左右两个之外的Fragment视图。
  32. * 即:滑到第3个Fragment时,第1个Fragment会被销毁视图,且只调用到这一步
  33. */
  34. if (f is ILazyInitFragment) {
  35. (f as ILazyInitFragment).getLazyInitModel()?.mInitialized = false
  36. }
  37. }
  38. /**
  39. * 设置生命周期状态
  40. */
  41. private fun setLifecycleState(fragment: Fragment, state: Int) {
  42. //首先判断是否已经实现 ILazyInitFragment 接口
  43. if (fragment is ILazyInitFragment) {
  44. (fragment as ILazyInitFragment).getLazyInitModel()?.setCurrentState(state)
  45. }
  46. }
  47. }

4. 使用

前面准备的这么充分,后面就可以行的方便了。

4.1 Fragment实现ILazyInitFragment接口(添加10行代码

  1. class AchieveZeroFragment : Fragment(), ILazyInitFragment {
  2. val TAG = this.javaClass.simpleName
  3. /*
  4. ******************************************************************************************************
  5. * 使用开始
  6. ******************************************************************************************************
  7. */
  8. private var mLazyInitModel: LazyInitModel? = null
  9. override fun getLazyInitModel(): LazyInitModel? {
  10. if (mLazyInitModel == null)
  11. mLazyInitModel = LazyInitModel(this)
  12. /*
  13. 还可以自定义LazyInitModel
  14. */
  15. // mLazyInitModel = CustomLazyInitModel(this)
  16. return mLazyInitModel
  17. }
  18. override fun setUserVisibleHint(isVisibleToUser: Boolean) {
  19. super.setUserVisibleHint(isVisibleToUser)
  20. //无法监听到这个方法,需要手动调用
  21. getLazyInitModel()?.setUserVisibleHint(isVisibleToUser)
  22. }
  23. override fun lazyInit() {
  24. /*
  25. 可以在该方法内调用需要懒加载的方法
  26. */
  27. tv_msg.text = TAG
  28. Timber.e("$TAG 初始化")
  29. }
  30. /*
  31. ******************************************************************************************************
  32. * 使用结束
  33. ******************************************************************************************************
  34. */
  35. override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
  36. return inflater.inflate(R.layout.fragment_common, container, false)
  37. }
  38. }

4.2 Activity注册监听(添加3行代码

  1. class AchieveActivity : AppCompatActivity() {
  2. val mAdapter = CommonFragmentPagerAdapter(
  3. supportFragmentManager, arrayListOf(
  4. AchieveZeroFragment(),
  5. AchieveOneFragment(),
  6. AchieveTwoFragment(),
  7. AchieveThreeFragment()
  8. )
  9. )
  10. val mLifecycleForLazyInitImpl = FragmentLifecycleForLazyInitImpl()
  11. companion object {
  12. fun start(context: Context) {
  13. val intent = Intent(context, AchieveActivity::class.java)
  14. context.startActivity(intent)
  15. }
  16. }
  17. override fun onCreate(savedInstanceState: Bundle?) {
  18. super.onCreate(savedInstanceState)
  19. setContentView(R.layout.activity_achieve)
  20. /*
  21. 注册Fragment生命周期监听
  22. */
  23. supportFragmentManager.registerFragmentLifecycleCallbacks(
  24. //传入我们实现的类
  25. mLifecycleForLazyInitImpl,
  26. /*
  27. 是否递归Fragment中的Fragment
  28. 我们这里不做处理了
  29. */
  30. false
  31. )
  32. supportFragmentManager.registerFragmentLifecycleCallbacks(FragmentLifecycleForLazyInitImpl(), false)
  33. vp.adapter = mAdapter
  34. }
  35. override fun onDestroy() {
  36. super.onDestroy()
  37. supportFragmentManager.unregisterFragmentLifecycleCallbacks(mLifecycleForLazyInitImpl)
  38. }
  39. }

哎~怎么添加这么多行代码?
别闹了~注释不能算吧,分行写不也是为了注释的清楚嘛!

  1. //创建对象
  2. val mLifecycleForLazyInitImpl = FragmentLifecycleForLazyInitImpl()
  3. //注册
  4. supportFragmentManager.registerFragmentLifecycleCallbacks(FragmentLifecycleForLazyInitImpl(), false)
  5. //反注册
  6. supportFragmentManager.unregisterFragmentLifecycleCallbacks(FragmentLifecycleForLazyInitImpl())

这样子就是3行了吧~

后语

  1. 实现依然不复杂,关键在于对Fragment的生命周期监听方式知不知道。
  2. 看着不多,写起来还真是费劲
  3. 能给点个赞就欢喜了~

源码地址

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注