实现Fragment懒加载(结合TabLayout+ViewPager)

时间:2021-7-5 作者:qvyue

引言

  TabLayout+ViewPager+Fragment是我们很常用的页面导航布局,通过Tab选中与否切换fragment页面,但由于ViewPager的缓存机制,会默认加载当前fragment相邻的两个fragment的数据。这有时候并不符合我们的业务需求,因此需要对fragment做懒加载,让其在点击tab切换fragment时(也就是当前fragment对用户可见的时候)只加载该页面数据。


验证

在未进行懒加载时,我们会发现在第一个Fragment可见的时候(此时未切换到第二个Tab栏),此时第二个Fragment的生命周期被调用情况如下:
实现Fragment懒加载(结合TabLayout+ViewPager)
增加这个setUserVisibleHint方法的log打印:
实现Fragment懒加载(结合TabLayout+ViewPager)

结论

onResume在Fragment中表示当前Fragment针对用户来说是否可见,但是由于ViewPager的缓存机制,观察生命周期,此方法已经没有意义了。
从Fragment1切换到Fragment2的log打印:
实现Fragment懒加载(结合TabLayout+ViewPager)
可以看出onResume方法并不决定布局是否可见,而是由setUserVisibaleHint方法的返回值来确定的。
那个Fragment的该方法返回true则Tab切换到哪个Fragment上。

因此需要在setUserVisibleHint中的参数为true的时候再去做数据加载


完整版的懒加载BaseFragment代码:

/**
 * @data on 4/28/21 9:58 AM
 * @auther KC
 * @describe BaseFragment,实现了Fragment懒加载
 */
open class BaseFragment : Fragment() {

    //表明fragment是否显示
    private var mIsVisibleToUser = false

    //表明view是否被加载
    private var mIsViewCreatetd = false

    //表明data是否被加载
    private var mIsDataLoaded = false

    /**
     * 是否view已被加载
     */
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mIsViewCreatetd = true
    }

    /**
     * 懒加载的关键
     * isVisibleToUser是否为true,则对应表明页面是否展示到当前Fragment。
     */
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        mIsVisibleToUser = isVisibleToUser
        lazyLoad()
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        if (mIsVisibleToUser && !mIsDataLoaded) {
            lazyLoad()
        }
    }

    /**
     * view和data清除
     */
    override fun onDestroyView() {
        super.onDestroyView()
        mIsViewCreatetd = false
        mIsDataLoaded = false
    }

    fun lazyLoad() {
        if (mIsViewCreatetd && mIsVisibleToUser && !mIsDataLoaded) {
            initData()
            mIsDataLoaded = true
        }
    }

    //开放要加载的数据
    open fun initData() {}
}

四个Fragment的代码雷同,只是tagStr改变了个序号

class Fragment1 : BaseFragment() {

    val tagStr = "Fragment1"

    val vBinding by lazy {
        Fragment1Binding.inflate(layoutInflater)
    }

    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        logd(tagStr,"setUserVisibleHint  返回 $isVisibleToUser")
    }

    override fun onAttach(context: Context) {  //对应onDetach()
        super.onAttach(context)
        logd(tagStr,"onAttach")
    }

    override fun onCreate(savedInstanceState: Bundle?) {  //对应onDestroy()
        super.onCreate(savedInstanceState)
        logd(tagStr,"onCreate")
    }

    override fun onCreateView(  //对应onDestroyView()
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        logd(tagStr,"onCreateView")
        return vBinding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {  //无对应方法
        super.onActivityCreated(savedInstanceState)
        logd(tagStr,"onActivityCreated")
    }

    override fun onStart() {  //对应onStop()
        super.onStart()
        logd(tagStr,"onStart")
    }

    override fun onResume() {  //对应onPause()
        super.onResume()
        logd(tagStr,"onResume")
    }

    override fun onPause() {
        super.onPause()
        logd(tagStr,"onPause")
    }

    override fun onStop() {
        super.onStop()
        logd(tagStr,"onStop")
    }

    override fun onDestroyView() {
        super.onDestroyView()
        logd(tagStr,"onDestroyView")
    }

    override fun onDestroy() {
        super.onDestroy()
        logd(tagStr,"onDestroy")
    }


    override fun onDetach() {
        super.onDetach()
        logd(tagStr,"onDetach")
    }

    override fun initData() {
        super.initData()
        toast("$tagStr 加载数据...")
    }
}

最后,附上Activity和PublicTabAdapter的代码:

Activity代码:
class Kotlin18 : AppCompatActivity() {

    val vBinding by lazy {
        ActivityKotlin18Binding.inflate(layoutInflater)
    }
    val fragments = ArrayList()
    val titles = ArrayList()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(vBinding.root)
        setTabLayout()
    }

    //设置TabLayout和ViewPager
    fun setTabLayout(){
        setTitleData()
        titles.forEach {
            vBinding.tabLayout.addTab(vBinding.tabLayout.newTab().setText(it))
        }
        fragments.add(Fragment1())
        fragments.add(Fragment2())
        fragments.add(Fragment3())
        fragments.add(Fragment4())
        vBinding.viewPager.adapter = PublicTabAdapter(supportFragmentManager,fragments,titles)
        vBinding.tabLayout.setupWithViewPager(vBinding.viewPager)
    }

    //设置tabTitles数据
    fun setTitleData(){
        titles.add("Tab1")
        titles.add("Tab2")
        titles.add("Tab3")
        titles.add("Tab4")
    }
}
PublicTabAdpter代码:
/**
 * @data on 4/23/21 9:35 PM
 * @auther KC
 * @describe TabLayout+ViewPager适配器
 */
class PublicTabAdapter(fm: FragmentManager?,
                       private val list_fragment: ArrayList,
                       private val list_Title: ArrayList) : FragmentPagerAdapter(fm!!) {
    override fun getItem(position: Int): Fragment {
        return list_fragment[position]
    }

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

    // 此方法用来显示tab上的名字
    override fun getPageTitle(position: Int): CharSequence? {
        return list_Title[position % list_Title.size]
    }
}
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。