Fragment在ViewPager下的懒加载方案

目录

面临的问题:

我们的预期是:

直接上我已经测试的方案:

1.FragmentStatePagerAdapter构造函数behavior参数设置为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

2.定义LazyResumeFragment,子fragment继承他进行管理即可

3.使用:

总结:


面临的问题:

TabLayout+ViewPager+FragmentStateAdapter是很常见的页面布局, 很多页面可以集中在一起,不断切换便能集中很多业务,但是面临一些问题:

  • 多个页面,如果有缓存,将会本地缓存很多数据,造成卡顿等;
  • 多个页面初始化,会出现大量请求,造成流量浪费;

简单来说就是,孙然我们滑动到了一个页面,但是viewPager两边的页面被加载了;

我们的预期是:

  • 只有fragment看到的时候才会加载页面,而且只有第一次看到的时候才会加载数据
  • 已经加载过的页面不会重复加载

直接上我已经测试的方案:

首先

1.FragmentStatePagerAdapter构造函数behavior参数设置为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

此种模式是官方推荐的模式,设置后,fragment可见和不可见只会走onResume和onPause函数,而不会走setUserVisibleHint

TestFragmentStatePagerAdapter.kt

class TestFragmentStatePagerAdapter(var titles:List<String> = ArrayList<String>(),var fragments:List<Fragment> = ArrayList<Fragment>(),var fm: FragmentManager): FragmentStatePagerAdapter(fm,
    BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

    override fun getCount(): Int {
        return fragments.size
    }

    override fun getItem(position: Int): Fragment {
        return fragments[position]
    }

    override fun getPageTitle(position: Int): CharSequence? {
        return titles[position]
    }
}

2.定义LazyResumeFragment,子fragment继承他进行管理即可
 

 LazyResumeFragment.kt

/***
 *  针对设置了BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式的fragment
 *  create by DragonForest on 2022/3/15
 */
abstract class LazyResumeFragment : Fragment() {
    private var mView: View? = null
    private val TAG = this.javaClass.simpleName
    private var isFirstShow = true
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (mView == null) {
            mView = LayoutInflater.from(context).inflate(getLayoutRes(), container, false)
        }
        initView()
        return mView
    }

    override fun onDestroyView() {
        super.onDestroyView()
        isFirstShow = true
    }

    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        Log.i(TAG,"setUserVisibleHint,isVisibleToUser:$isVisibleToUser ")
    }

    override fun onResume() {
        super.onResume()
        Log.i(TAG,"onResume")
        if (isFirstShow) {
            isFirstShow = false
            initLoadData()
        }
        onVisible()
    }

    override fun onPause() {
        super.onPause()
        Log.i(TAG,"onPause")
        onInVisible()
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        Log.i(TAG,"onAttach")
    }

    override fun onDetach() {
        super.onDetach()
        Log.i(TAG,"onDetach")
    }

    /**
     * 获取资源文件
     */
    abstract fun getLayoutRes(): Int

    /**
     * 初始化view
     */
    abstract fun initView()

    /**
     * 初始化数据
     *   初次请求接口加载数据请在这里写
     */
    abstract fun initLoadData()

    /**
     * fragment显示在前台时
     */
    abstract fun onVisible()

    /**
     * fragment隐藏时
     */
    abstract fun onInVisible()
    
}

子fragment:

/***
 *  create by DragonForest on 2022/3/15
 */
class HomeFragment1: LazyVisibleHintFragment() {
    val TAG = this.javaClass.simpleName
    val uiHandler: Handler = Handler(Looper.getMainLooper())

    override fun getLayoutRes(): Int {
        return R.layout.fragment_home1
    }

    override fun initView() {
        Log.i(TAG,"initView")
        tv_loading?.text = "未初始化"
        iv_result?.visibility = View.GONE
    }

    override fun initLoadData() {
        Log.i(TAG,"initLoadData")
        tv_loading?.text = "正在加载..."
        iv_result?.visibility = View.GONE
        uiHandler.postDelayed({
            tv_loading?.text = "加载完成"
            iv_result?.visibility = View.VISIBLE
        },2000L)
    }

    override fun onVisible() {
        Log.i(TAG,"onVisible")
    }

    override fun onInVisible() {
        Log.i(TAG,"onInVisible")
    }
}

3.使用:

class FragmentTestActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_fragment_test)
        initView()
    }

    private fun initView() {
        var titles = arrayOf("首页1","首页2","首页3","首页4")
        var fragments = arrayOf(HomeFragment1(),HomeFragment2(),HomeFragment3(),HomeFragment4())
        viewPager.adapter = TestFragmentStatePagerAdapter(titles.toList(),fragments.toList(),supportFragmentManager)
        tablayout.setupWithViewPager(viewPager)
    }
}

这样一个懒加载的案例就完成了;

总结:

  • 在BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式下可以控制fragment可见和不可见只会调用onResume和onPause,  实现懒加载比较容易; 如果设置成BEHAVIOR_SET_USER_VISIBLE_HINT, setUserVisibleHint将会被调用,需要特殊处理,建议在新建一个LazyVisibleHintFragment基类来管理; 

        建议最好使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT模式, 因为BEHAVIOR_SET_USER_VISIBLE_HINT已经被官方废弃, 而且适配这种模式的懒加载较复杂,会背离fragment设计初衷,比如onResume中本来就是用来显示页面的

  • 本次只处理了fragment在viewPager中的懒加载, 因为这是最常见的; 还有几种场景,比如show,add时候的懒加载,嵌套fragment的懒加载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龍林1102

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值