Search code examples
androidandroid-viewpagerandroid-viewpager2fragment-lifecyclefragmentstateadapter

Fragment instances are kept in viewPager2 when host fragment removed


Have one activity app, where I have HomeFragment from which I open HostFragment, and HostFragment has ViewPager2 with 3 fragment items TabFragment1, TabFragment2 and TabFragment3.

When I open the HostFragment, and then go back, my tabFragments' instances are not removed. Below is the logs from lifecycles

navController.navigate(directionToHostFragment)

  1. HostFragment OnStart HostFragment{c37542c}
  2. TabFragment1 OnStart TabFragment1 {f41b08}

navController.popBackStack()

  1. HostFragment OnPause HostFragment{c37542c}
  2. HostFragment OnStop{c37542c}
  3. HostFragment OnDestroy {c37542c}

navController.navigate(directionToHostFragment) Blockquote

  1. HostFragment OnStart{2670c03}
  2. TabFragment1 OnStart{f45b87d}

navController.popBackStack()

  1. HostFragment OnPause{2670c03}
  2. HostFragment OnStop{2670c03}
  3. HostFragment onDestroy{2670c03}

From ids you can see that there is a new TabFragment1 instance and old one haven't destroyed(I have logs in onPause(), onStop() etc.).

Some code snippets: Adapter for viewPager2 I used -

class LessonTabsAdapter(fragmentActivity: FragmentActivity, val pages: List<BaseFragment>) :
    FragmentStateAdapter(fragmentActivity) {
    override fun getItemCount() = pages.size
    override fun createFragment(position: Int) = pages[position]
}

Some part from TabFragment1

class TabFragment1 : BaseFragment(R.layout.fragment_tab_1) {
    private var mediaPlayer: MediaPlayerClass? = null
    private lateinit var player: SimpleExoPlayer

    private val viewModel by sharedViewModel<SomeViewModel>()
    private val binding by viewDataBinding(FragmentTab1Binding::bind)
    //Overriden onViewCreated(..) and some private methods 
}

So any hints how to deal with this problem?


Solution

  • When you open the HostFragment the ViewPager2 creates a fragment in the lifecycle provided. In this case you are passing activity as the parameter so, it is creating the fragments in Activity's lifecycle. You can check the same by printing the activity?.supportFragmentManager?.fragments list. If you want to couple the ViewPager2's childs with HostFRagment, you need to pass the fragments instance to the FragmentStateAdapter. Check the function 2 that I have added. The best way to implement the ViewPager2 is by using function 3.

    1..
    public FragmentStateAdapter(@NonNull FragmentActivity fragmentActivity) {
      this(fragmentActivity.getSupportFragmentManager(),fragmentActivity.getLifecycle());
    }
    
    2.//
    public FragmentStateAdapter(@NonNull Fragment fragment) {
      this(fragment.getChildFragmentManager(), fragment.getLifecycle());
    }
    
    3.//
    public FragmentStateAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
       mFragmentManager = fragmentManager;
       mLifecycle = lifecycle;
       super.setHasStableIds(true);
    }