105

Since API 27 FragmentPagerAdapter is deprecated. What's the best alternative to use for this?

In my case, I understand something like super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) would need to be used, but I don't know where within my code this needs to go.

I got these imports in my class:

import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter

but FragmentPagerAdapter in class MyViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager){ is crossed out.

class MyViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager){
        private val fragmentList : MutableList<androidx.fragment.app.Fragment> = ArrayList()
        private val titleList : MutableList<String> = ArrayList()

        override fun getItem(position: Int): androidx.fragment.app.Fragment {
            return fragmentList[position]
        }

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

        fun addFragment(fragment: androidx.fragment.app.Fragment, title: String){
            fragmentList.add(fragment)
            titleList.add(title)
        }

        override fun getPageTitle(position: Int): CharSequence? {
            return titleList[position]
        }
    }
wbk727
  • 8,017
  • 12
  • 61
  • 125

7 Answers7

152

UPDATE 2021-06-14: At this point, ViewPager itself is all but deprecated. Technically, ViewPager is not deprecated, but the two concrete PagerAdapter implementations — FragmentPagerAdapter and FragmentStatePagerAdapter — are deprecated. Ideally, switch to something else, such as ViewPager2 or the pager composable in Accompanist.

Replace:

class MyViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager)

with:

class MyViewPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

(assuming that MyViewPagerAdapter does not need this value to be configurable)

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 9
    Why i need this after add this @SuppressLint("WrongConstant") after adding this in constructor FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT? – Asad Mukhtar Dec 03 '19 at 19:28
  • 1
    @AsadMukhtar: I do not know, sorry. You might consider asking a separate Stack Overflow question, where you can provide a [mcve] showing what you are trying and where you needed to apply that annotation. – CommonsWare Dec 03 '19 at 23:04
  • 1
    We cannot use FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT anymore as FragmentPagerAdapter is also deprecated now. – Feroz Khan Jun 14 '21 at 12:13
  • 1
    @FerozKhan: Yes, I believe that at this point `ViewPager` itself is deprecated. – CommonsWare Jun 14 '21 at 12:20
  • 1
    Alternately, you can say `@SuppressWarnings("deprecation")` in cases where `ViewPager2` breaks your app behaviors :D – EpicPandaForce Jun 14 '21 at 12:26
  • 1
    @EpicPandaForce: Agreed, though eventually Google is going to stop updating `androidx.viewpager:viewpager`. Even then, you might be able to use the last-shipped version for a while, before some transitive dependency or something breaks the build as you update other stuff. So, we don't have to race and replace `ViewPager` this week, but I would recommend it sometime in the next year or two. – CommonsWare Jun 14 '21 at 12:31
16

Switch to ViewPager2 with FragmentStateAdapter.

Here is the XML view:-

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>
class AdapterTabPager(activity: FragmentActivity?) : FragmentStateAdapter(activity!!) {
    private val mFragmentList: MutableList<Fragment> = ArrayList()
    private val mFragmentTitleList: MutableList<String> = ArrayList()
    
    public fun getTabTitle(position : Int): String{
        return mFragmentTitleList[position]
    }

    fun addFragment(fragment: Fragment, title: String) {
        mFragmentList.add(fragment)
        mFragmentTitleList.add(title)
    }

    override fun getItemCount(): Int {
        return mFragmentList.size
    }

    override fun createFragment(position: Int): Fragment {
        return mFragmentList[position]
    }
}

Here is the way to instantiate ViewPager:-

val adapter = AdapterTabPager(activity)
        adapter.addFragment(categoryFragment, "Category")
        adapter.addFragment(brandFragment, "Brand")

        rootView.viewpager.adapter = adapter
        rootView.viewpager.currentItem = 0
        TabLayoutMediator(rootView.tabs, rootView.viewpager) { tab, position ->
            tab.text = adapter.getTabTitle(position)
        }.attach()

Bharat Lalwani
  • 1,277
  • 15
  • 17
14

The javadocs actually has the following deprecation notice on FragmentPagerAdapter:


This class is deprecated.

Switch to ViewPager2 and use FragmentStateAdapter instead.


Kiskae
  • 24,655
  • 2
  • 77
  • 74
5

Need to switch to ViewPager2, they have a migration guide here.

https://developer.android.com/training/animation/vp2-migration#java

  • Henrik Bøgelund Lavstsen, a link to a solution is welcome, but please ensure your answer is useful without it: [add context around the link](//meta.stackexchange.com/a/8259) so your fellow users will have some idea what it is and why it is there, then quote the most relevant part of the page you are linking to in case the target page is unavailable. [Answers that are little more than a link may be deleted.](/help/deleted-answers) – STA May 30 '21 at 06:25
4

If you used this path New > Activities > Tabbed Activity so you need some changes:

1- XML

before

<androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@string/pages"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

after

<androidx.viewpager2.widget.ViewPager2
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@string/pages"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

2- New Adapter As @Bharat Lalwani wrote below:

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter

class ScreenSlidePagerAdapter(activity: FragmentActivity?) : FragmentStateAdapter(activity!!) {
    private val mFragmentList: MutableList<Fragment> = ArrayList()
    private val mFragmentTitleList: MutableList<String> = ArrayList()

    fun getTabTitle(position : Int): String{
        return mFragmentTitleList[position]
    }

    fun addFragment(fragment: Fragment, title: String) {
        mFragmentList.add(fragment)
        mFragmentTitleList.add(title)
    }

    override fun getItemCount(): Int {
        return mFragmentList.size
    }

    override fun createFragment(position: Int): Fragment {
        return mFragmentList[position]
    }
}

3- Main Activity

before

val sectionsPagerAdapter = SectionsPagerAdapter(this, supportFragmentManager)
    val viewPager: ViewPager = binding.viewPager
    viewPager.adapter = sectionsPagerAdapter
    val tabs: TabLayout = binding.tabs
    tabs.setupWithViewPager(viewPager)

after

val adapter = ScreenSlidePagerAdapter(this)

    adapter.addFragment( PlaceholderFragment.newInstance( 1),"Brand")
    adapter.addFragment( PlaceholderFragment.newInstance( 2),"Brand2")
    val viewPager: ViewPager2 = binding.viewPager
    viewPager.adapter = adapter
    viewPager.currentItem = 0
    val tabs: TabLayout = binding.tabs
    TabLayoutMediator(tabs, viewPager) { tab, position ->
        tab.text = adapter.getTabTitle(position)
    }.attach()

4- Then you can delete SectionsPagerAdapter class

Mori
  • 2,653
  • 18
  • 24
2

It seems like not only the constructor without behavior, but the class FragmentPagerAdapter (which can consume a good amount of memory by keeping Fragments in memory), and FragmentStatePagerAdapter are both in deprecation stage. I wonder what can be used to extend abstract class PagerAdapter to extend codebase lifespan.

ricardopereira
  • 11,118
  • 5
  • 63
  • 81
1

You can use FragmentStateAdapter(fragment)

class YourViewPagerAdapter(fragment: Fragment, val mFragmentList: Array<String>, val viewPager: ViewPager2) :  FragmentStateAdapter(fragment){

    override fun getItemCount(): Int {
        return mFragmentList.size
    }

    override fun createFragment(position: Int): Fragment {
        when(position){
            0 -> return YourFirstTabFragment()
            1 -> return YourSecondTabFragment()
            2 -> return YourThirdTabFragment()

        }
        return YourFirstTabFragment()
    }


}
Tippu Fisal Sheriff
  • 2,177
  • 11
  • 19