androidkotlinandroid-viewpager2fragmentstateadapter

findFragmentByTag keeps returning Null in Android using ViewPager


I was trying to pass data from the Parent Activity to the viewPager, and I found a solution using findFragmentByTag but it returns Null and I'm not sure what I missed.

The example I found used a deprecated FragmentPagerAdapter and I think maybe that's why my implementation doesn't work, so I'm looking for a way forward.

(supportFragmentManager.findFragmentByTag(tag) as StopwatchFragment?)?.displayData(
            min!!,
            sec!!,
            millis!!
        )

is null

Main Activity

class MainActivity : AppCompatActivity(), StopwatchListener {
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
       ...
        binding.viewPagerMain.adapter = PageAdapter(supportFragmentManager, lifecycle)
       
    }
...
 override fun getTheTime(min: String?, sec: String?, millis: String?) {
        val tag =
            "android:switcher:" + R.id.view_pager_main.toString() + ":" + binding.viewPagerMain.currentItem
        Log.d("Main", tag)
        (supportFragmentManager.findFragmentByTag(tag) as StopwatchFragment?)?.displayData(
            min!!,
            sec!!,
            millis!!
        )
    }
}

PageAdapter

class PageAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
    FragmentStateAdapter(fragmentManager, lifecycle) {

    override fun getItemCount() = 3

    override fun createFragment(position: Int): Fragment {
        return when (position) {
            0 -> {
                RepsFragment()
            }
            1 -> {
                StopwatchFragment()
            }
            2 -> {
                TimerFragment()
            }
            else -> {
                RepsFragment()
            }
        }
    }
}

Solution

  • val tag =
            "android:switcher:" + R.id.view_pager_main.toString() + ":" + binding.viewPagerMain.currentItem
    

    This is valid for the ViewPager not ViewPager2.

    In order to do that for ViewPager2, you need:

    val tag = "f$pageId"
    

    And this requires to have unique IDs for the pages, for simplicity you can set them as the ViewPager positions; to do so override getItemId() of the adapter:

    class PageAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
        FragmentStateAdapter(fragmentManager, lifecycle) {
    
        // ... 
    
        override fun getItemId(position: Int): Long {
            return position.toLong()
        }
    }
    

    And then the pageId will be the current page (or any page position you want), and hence the tag would be:

    val tag = "f$binding.viewPagerMain.currentItem"