The first public number: Hacker 567

Author: A good elm’s elm

If you like it, please pay attention to it, appreciate it and click on it

Reading time: 1738 words, 6 minutes

Lazy loading of fragments is usually used when you manage multiple Fragment interfaces in a single Activity using a ViewPager. When each Fragment is very complex, it is common to load the first Fragment first, and the next Fragment when it is visible, in order to ensure the overall flow of the Activity. “Unavailable” (setUserVisiable() method and onViewCreated method are used when thinking of lazy loading in fragments, but ViewPager2+Fragment does not work. Due to various historical reasons, there are many ways to nest fragments now. Therefore, here we study these ways and see if we can find an appropriate lazy loading method as the implementation of my BaseLazyFragment, which is compatible with these ways of nesting.

Of course, my starting point is still to explore the life cycle. Let’s take a look at the Fragment lifecycle:

class LifeCycleFragment : Fragment() {
    companion object {
        fun create(position: Int): LifeCycleFragment {
            val fragment = LifeCycleFragment()
            fragment.arguments = bundleOf(Pair("p", position))
            return fragment
        }
    }

    var position: String = ""override fun onAttach(context: Context) { position = arguments? .getInt("p").toString()
        super.onAttach(context)
        Log.d("ResumeOnly"."Fragment${position}onAttach")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("ResumeOnly"."Fragment${position}onCreate") } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup? , savedInstanceState: Bundle? ) : View? { Log.d("ResumeOnly"."Fragment${position}onCreateView")
        return TextView(activity).apply {
            text = position
            layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
            textSize = 100f
            typeface = Typeface.DEFAULT_BOLD
            gravity = Gravity.CENTER
        }
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        Log.d("ResumeOnly"."Fragment${position}onActivityCreated")
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        Log.d("ResumeOnly"."Fragment${position}onViewCreated")
    }


    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        Log.d("ResumeOnly"."Fragment${position}isVisibleToUser$isVisibleToUser")
    }

    override fun onStart() {
        super.onStart()
        Log.d("ResumeOnly"."Fragment${position}onStart")
    }

    override fun onResume() {
        super.onResume()
        Log.d("ResumeOnly"."Fragment${position}onResume")
    }

    override fun onPause() {
        super.onPause()
        Log.d("ResumeOnly"."Fragment${position}onPause")
    }

    override fun onStop() {
        super.onStop()
        Log.d("ResumeOnly"."Fragment${position}onStop")
    }

    override fun onDestroyView() {
        super.onDestroyView()
        Log.d("ResumeOnly"."Fragment${position}onDestroyView")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("ResumeOnly"."Fragment${position}onDestroy")}}Copy the code

First nested :ViewPager+FragmentPagerAdapter(FA,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) ‘s lifecycle

Second nesting: ViewPager+FragmentPagerAdapter(FM)

Third nesting: ViewPager2+Fragment

Make a generic BaseLazyFragment

Through the above three nested logs. We just need to finalize one thing: the default value for mUserVisibleHint

As expected, all we need to do is call a lazyLoad method in both onResume and setUserVisibleHint, and determine the value of mUserVisibleHint and the value of loaded. Another point to note is that setUserVisibleHint’s method call timing may not be within the Fragment’s lifetime

This method may be called outside of the fragment lifecycle. and thus has no ordering guarantees with regard to fragment lifecycle method calls

So we also need to check whether the root layout is null, and the final implementation code is as follows:

abstract class BaseLazyFragment : Fragment() {
    private var cacheView: View? = null
    private var loaded: Boolean = falseoverride fun onCreateView( inflater: LayoutInflater, container: ViewGroup? , savedInstanceState: Bundle? ) : View? {if (cacheView == null) {
            cacheView = inflater.inflate(layoutId(), container, false)}return cacheView
    }


    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        lazyLoad()
    }

    override fun onResume() {
        super.onResume()
        lazyLoad()

    }

    private fun lazyLoad() {
        if(userVisibleHint && ! loaded&& cacheView ! = null) { initView() initData() loaded =true
        }
    }

    abstract fun layoutId(): Int

    abstract fun initData()

    abstract fun initView()
}
Copy the code

Finally, let’s take a look at a lazy implementation of these three nested patterns:

This code is in Google ViewPager2 code based on the new three pages for log printing, code address: github.com/luorenyu/Ex…