Tuesday, 11 May 2021

Fragment containing ViewPager reloads when switched back from another Fragment using NavGraph - Jetpack Navigation

(TLDR provided below)

I've a complex Activity-Fragment Structure which was earlier 3 Activities, now converted to three Fragments. Because it was complex, heavy and a lot of data was interchanged, I'd changed it to the new Navigation UI based structure looking at Google's Sunflower and it is much cleaner now and works faster and better.

My app's flow can easily be understood by the image provided below (Nav Graph provided below): Image describing my app's flow

Main Fragment is Fragment1 which contains the ViewPager2 with FragmentStateAdapter and 5 Fragments inside it. The problem is Fragment1 completely reloads when user comes back to it from Fragment2.

Two possible scenarios:

  1. When user opens Fragment2 from Fragment1 and comes back, Fragment1 which contains the ViewPager completely reloads which takes 2-3 seconds as it contains 5 Fragment which further consists of Fragment and is the problem I need the solution of.

  2. As I'm using ViewBinding, If I check whether the binding has been initialized or not (code below) and pass initialized instead, the Fragment1 doesn't reload but Fragments inside the ViewPager get issues like any button in any Fragment will stop working, the TabLayout will stop working, Child ViewPager2s in FragmentB, FragmentD and FragmentE will stop working.

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        if (!this::binding.isInitialized) {
            //initializing Binding here
        }
        return binding.root
    }
    

  1. Graph nav_main.xml with pictorial representation: enter image description here

     <navigation xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         xmlns:tools="http://schemas.android.com/tools"
         android:id="@+id/nav_main"
         app:startDestination="@id/fragment_1">
    
         <fragment
             android:id="@+id/fragment_1"
             android:name="com.x.x.fragments.Fragment1"
             tools:layout="@layout/fragment_1">
    
             <action
                 android:id="@+id/action_fragment_1_to_fragment_2"
                 app:destination="@id/fragment_2"
                 app:enterAnim="@anim/slide_in_right"
                 app:exitAnim="@anim/slide_out_left"
                 app:popEnterAnim="@anim/slide_in_left"
                 app:popExitAnim="@anim/slide_out_right" />
             <action
                 android:id="@+id/action_fragment_1_to_fragment_3"
                 app:destination="@id/fragment_3"
                 app:enterAnim="@anim/slide_in_right"
                 app:exitAnim="@anim/slide_out_left"
                 app:popEnterAnim="@anim/slide_in_left"
                 app:popExitAnim="@anim/slide_out_right" />
    
         </fragment>
    
         <fragment
             android:id="@+id/fragment_2"
             android:name="com.x.x.fragments.Fragment2"
             tools:layout="@layout/fragment_2">
    
             <action
                 android:id="@+id/action_fragment_2_to_fragment_3"
                 app:destination="@id/fragment_3"
                 app:enterAnim="@anim/slide_in_right"
                 app:exitAnim="@anim/slide_out_left"
                 app:popEnterAnim="@anim/slide_in_left"
                 app:popExitAnim="@anim/slide_out_right" />
    
             <argument
                 android:name="DataModel"
                 app:argType="com.x.x.models.DataModel" />
    
             <argument
                 android:name="Tab"
                 app:argType="integer" />
    
         </fragment>
    
         <fragment
             android:id="@+id/fragment_3"
             android:name="com.x.x.fragments.Fragment3"
             tools:layout="@layout/fragment_3">
    
             <argument
                 android:name="DataModel"
                 app:argType="com.x.x.models.DataModel" />
    
         </fragment>
    
     </navigation>
    
  2. activity_main.xml

     <layout xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto">
    
         <androidx.fragment.app.FragmentContainerView
             android:id="@+id/nav_host"
             android:name="androidx.navigation.fragment.NavHostFragment"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             app:defaultNavHost="true"
             app:navGraph="@navigation/nav_main" />
    
     </layout>
    

(TL;DR) So, My question is how can I prevent reloading of the FragmentA which contains the ViewPager2 and ensure that Fragments inside it will not stop working? I've no problem if I can only prevent reloading of child FragmentC, the default one on which app opens, others can reload. Please note I've read almost all the (somewhat) similar questions and answers and none helps.

EDIT - I tried both of the answers of this question which I though of getting success with, but nothing worked.

EDIT2 - Found a similar popular question without any working solution - Viewpager2 with fragments and Jetpack navigation: Restore fragments instead of recreating them .

EDIT3 - I also tried saving the instance of the ViewPager's adapter using the saveState() in onStop() and onSaveInstanceState() and restoring it using restoreState() but then, it shows nothing but a white screen.



from Fragment containing ViewPager reloads when switched back from another Fragment using NavGraph - Jetpack Navigation

No comments:

Post a Comment