实现Fragment懒加载(结合TabLayout+ViewPa

作者: 千夜零一 | 来源:发表于2021-05-06 10:03 被阅读0次

    引言

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


    验证

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

    结论

    onResume在Fragment中表示当前Fragment针对用户来说是否可见,但是由于ViewPager的缓存机制,观察生命周期,此方法已经没有意义了。
    从Fragment1切换到Fragment2的log打印:
    可以看出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<Fragment>()
        val titles = ArrayList<String>()
    
        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<Fragment>,
                           private val list_Title: ArrayList<String>) : 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]
        }
    }
    

    相关文章

      网友评论

        本文标题:实现Fragment懒加载(结合TabLayout+ViewPa

        本文链接:https://www.haomeiwen.com/subject/xavrdltx.html