Navigation Component prevent to recreate fragment on back press
O

4

39

I'm using the Jetpack Navigation Component in my project with a single activity and some fragments.

I have a fragment with a list that fills from server side. I call getDataFromServer on the onViewCreated method then, when a user clicks on an item, a new fragment shows.

The problem is that when I press the back button, onViewCreated is called again in my list fragment.

So, how can I prevent my first fragment from recreating again? I don't want unnecessary onViewCreated calls.

Orvie answered 6/2, 2019 at 12:9 Comment(8)
use onActivityCreated function by overriding it in the fragment of yours and get your getDataFromServer there maybe!Alcaide
@Rizwanatta it is a good trick, I'll do it, but I'm waiting for maybe better answers to .thanksOrvie
Since you are using Navigation Component, you should probably use ViewModels aswell. It makes live much more easierInexpungible
This is why they invented ViewModel + fragment.getViewLifecycleOwner().Microcircuit
so where should I tell to ViewModel to get the data? @MicrocircuitOrvie
You can take some inspiration from NetworkBoundResource, where it is an effect of observing the LiveData inside the ViewModelMicrocircuit
@Microcircuit thanks, google sample was good, I think I have to get the first page of my list in view model constructor, and for next pages, I can do just like pagination. hope view model doesn't create again :D, because, in google sample, ViewModel initialized at onActivityCreated, but in my case list fragment shown if the user clicked on some buttonsOrvie
If popStackBack() is called instead your old fragment will only get its onResume() called instead, else if it had been destroyed you need override onSaveInstanceState/onRestoreInstanceStateMasseuse
O
7

Of course, we can not prevent calling oncrateView, but there is a simple way. Instead of calling view.loadData() in onCreateView or other lifecycle methods we can call it while initializing ViewModel

this article helped me to know ViewModel better 5 common mistakes when using Architecture Components

Update:

The current navigation component (V 2.3.0) doesn't support this feature, it always kills the fragment while navigating to another fragment. Imagine you have google map in Fragment A so each time you returns to the Fragment it initialized again and the camera moves to the user location!! (what a bad idea).

So the best way is not to use the navigation component if you have the same issue.

Navigation, Saving fragment state, GitHub issue

Update 2:

In some cases like Filters or pagination, we can use Transformations like switchMap in our ViewModel instead of getting data in init function.

Update 3:

If you have to call a function to load data from a source, there are lots of ways to prevent call that function again, the first and easiest way is instead of calling getData() in your view, do it your ViewModel init function. the second one is using lazy variables and another one is using SwitchMap on livedata. for more information you can find all solutions here

Orvie answered 18/3, 2020 at 17:40 Comment(4)
did you find any solution?Smithsonite
@Smithsonite No, there isn't any solution for this issue. but you can do it with some tricks. for example instead of calling getItems() from fragment do it in ViewModel init function or use transformations like switch map in your view model.Orvie
Even with ViewModel we are still recreating base/home fragment at the end which can be very expensive am I right?La
The article in Update #3 is a gem :)Ungrudging
G
0

You can't prevent calling onViewCreated method or any method of your fragment when back button pressed so you should better use view model with your list fragment and get data from server in your view model. Avoid getting data from server in your fragment since you already using Navigation UI.

Genoa answered 7/2, 2019 at 2:50 Comment(5)
so where should I tell to ViewModel to get the data?Orvie
In view model class. maybe you learn about view model it's a better approach.Genoa
I mean in fragment where should I tell to view model? I have pagination too. ok in my view model I get the data, but when fragment recreate again in the onViewCreated method I tell ViewModel to get the data, and it gonna get it, but I have it, and also I have pagination, How can I know that getting data is for pagination or not?Orvie
look at this gist viewmodel and mainFragmentGenoa
Even with ViewModel it doesn't prevent the fact that the base/home fragment view is being recreated which can be very expensive right?La
D
0

Maybe you have activate the graph.

app:popUpTo="@+id/nav_fingerprint_capture"
app:popUpToInclusive="true"
Duaneduarchy answered 20/2, 2020 at 21:39 Comment(0)
A
-1

Jetpack navigation component replaces the fragments. It does not add the fragments to stack. So when you open Fragment B from Fragment A and click back button in Fragment B, then Fragment A gets recreated.

If there is an API call in Fragment A and you do not want to make API call on every fragment recreation then you can save the API response in viewmodel and reuse the response when fragment gets recreated.

Example:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    if(foodViewModel.foodDataList.isEmpty()) {
        //make API call here and
        //save the response in foodViewModel.foodDataList
    } else {
        //use the saved response from viewmodel
        //and populate recyclerview
    }
Alexia answered 20/4, 2021 at 12:42 Comment(2)
This does not prevent the fact that you are populating the fragment view once more which can be very expensive.La
@MihaeKheel Yes, I know that. I do not see any other possible solution for this problem. By nature, Jetpack Navigation replaces fragments.Alexia

© 2022 - 2024 — McMap. All rights reserved.