FragmentStateAdapter and ViewPager2 is loading fragment slower than FragmentStatePagerAdapter and ViewPager

1.1k Views Asked by At

In my app, am showing list of month calendar which can be scrollable to previous and next month. While swiping to previous and next, my fragments are loading smoothly and without any delay if I use FragmentStatePagerAdapter and ViewPager but it's now deprecated. So, I updated

ViewPager to ViewPager2 

FragmentStatePagerAdapter to FragmentStateAdapter 

After updating, I can see there is a delay in loading the fragments while swiping previous and next. But the same code works smoothly with FragmentStatePagerAdapter and ViewPager. I also tried mViewPager2.setOffscreenPageLimit(//Interger Value//) but no help.

Please assist me.

Using FragmentStateAdapter and ViewPager2 Using FragmentStatePagerAdapter and ViewPager

fragment_employee_months_holder

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/fragment_months_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true"
        android:focusable="true" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:backgroundTint="@color/colorPrimary" />

</RelativeLayout>

EmployeeSummaryAdapter

class EmployeeSummaryAdapter(
    fragment: Fragment,
    private val mCodes: List<String>,
    private val mListener: NavigationListener,
    private val progressBarInterface: ProgressBarInterface
) : FragmentStateAdapter(fragment) {

    private val mFragments = SparseArray<EmployeeSummaryFragment>()

    override fun createFragment(position: Int): EmployeeSummaryFragment {
        val bundle = Bundle()
        val code = mCodes[position]
        bundle.putString(DAY_CODE, code)

        val fragment = EmployeeSummaryFragment(progressBarInterface)
        fragment.arguments = bundle
        fragment.listener = mListener
        mFragments.put(position, fragment)
        
        return fragment
    }

    override fun getItemCount(): Int = mCodes.size

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }
}

EmployeeSummaryFragmentHolder

class EmployeeSummaryFragmentHolder : MyFragmentHolder(), NavigationListener, ProgressBarInterface {

    private var viewPager2: ViewPager2? = null
    private lateinit var mEmployeeSummaryAdapter: EmployeeSummaryAdapter
    private lateinit var mView: View

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        currentDayCode = Formatter.getTodayCode()
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mView = inflater.inflate(R.layout.fragment_employee_months_holder, container, false)
        viewPager2 = mView.fragment_months_viewpager
        viewPager2!!.id = (System.currentTimeMillis() % 100000).toInt()

        Handler(Looper.getMainLooper()).postDelayed({
            setupFragment()
        }, 0)

        return mView
    }

    private fun setupFragment() {
        val codes = getMonths(currentDayCode)
        mEmployeeSummaryAdapter = EmployeeSummaryAdapter(this, codes, this, this)
        viewPager2.apply {
            viewPager2!!.adapter = mEmployeeSummaryAdapter

            val myPageChangeCallback = object : ViewPager2.OnPageChangeCallback() {
                override fun onPageScrollStateChanged(state: Int) { }
                override fun onPageScrolled(position: Int, positionOffset: Float, 
                                              positionOffsetPixels: Int) { }
                override fun onPageSelected(position: Int) {   }
            }
            viewPager2!!.registerOnPageChangeCallback(myPageChangeCallback)
        }
    }
}

EmployeeSummaryFragment

class EmployeeSummaryFragment(val progressBarInterface: ProgressBarInterface) :
    Fragment(), MonthlyCalendar {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_employee_month, container, false)
        ...
        ...        
        return view
    }

    override fun onResume() {
        super.onResume()
        ...
        ...
    }
}
2

There are 2 best solutions below

4
On BEST ANSWER

I tried to look into your code and I didn't find anything suspicious, but you definitely need to set your mViewPager2.setOffscreenPageLimit(//Interger Value//) into your EmployeeSummaryFragmentHolder.

viewpager2.offscreenPageLimit = 2
0
On

It would be more optimized, if you could check the mView is already initialized.

You can simply add this:

if(mView == null){
    mView = inflater.inflate(R.layout.fragment_employee_months_holder, container, false)
}