3

(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 thought 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.

EDIT4 - I've searched their Github issues as well, found no solution. Is the only solution I've is to go back to Activities? Is there nothing to do with these Fragments?

Lalit Fauzdar
  • 5,953
  • 2
  • 26
  • 50
  • You can do it with fragments (and other custom navigation frameworks that may wrap Fragments), but you cannot do it with Jetpack Navigation (without writing a custom navigator, which you probably won't) – EpicPandaForce May 12 '21 at 11:06
  • Hey @EpicPandaForce So, how do you suggest going with the Fragments way, using a ViewPager like mechanism where it doesn't stop the previous Fragment? As in the Navigation, it calls `onStop()` when a fragment is switched to back stack and hence, doesn't work properly even by maintaining reference of previous view. And this custom Navigator seems interesting, can't I override the default fragment behaviour and prevents it from stopping even on backstack? – Lalit Fauzdar May 12 '21 at 11:20
  • Well the behavior is inherent to using `replace().addToBackStack()`, if it was possible to use `add(new).hide(current)` on forward, and `remove(current).show(previous)` on back, then you can keep fragments without killing them. Bottom navigation currently can only keep fragments if you use nested child fragments. I'd love to link resources but apparently "self-attribution" is frown upon on this site, which is why I don't post here often anymore. – EpicPandaForce May 12 '21 at 11:50
  • So, if I create a custom navigator and override the default procedure to load the fragment of the fragment manager, at least in theory, this can be possible with my current scenario, I'll definitely check this custom navigator out before going with the Fragment way, Thank you, sir, and btw, any resources you share that can help are surely welcome. – Lalit Fauzdar May 12 '21 at 12:20
  • Just add your fragments normally without navgraph then you can achieve what yuu want. – Shivam Yadav May 16 '21 at 07:33
  • @LalitFauzdar check out this answer, might help. The user claims it as google's recommended solution, https://stackoverflow.com/a/64142496/6172439 – Darshan Miskin May 17 '21 at 09:36
  • @DarshanMiskin I'd already checked it out before posting this question, this is meant for `BottomNavigationView`. – Lalit Fauzdar May 17 '21 at 13:14
  • @LalitFauzdar from what I understood by that answer, apart from your main activity, the fragment1 or it's child which has multiple fragments inside it, in your case should have a nav-graph of it's own. – Darshan Miskin May 17 '21 at 14:01
  • 1
    @EpicPandaForce Hey, I had found a solution to this problem about two days later when you commented but forgot to post it because of covid. This upvote remimded me of this question, Thank you for your suggestion, I had created a custom navigator and instead of replacing the fragment, I hide it and it works flawlessly. I'll answer it later. Found no answer even on the official repo, but you helped.. – Lalit Fauzdar Jun 26 '21 at 19:43

0 Answers0