musooff
musooff

Reputation: 6852

Navigation Component Lifecycle

I have been trying out Navigation Component for a while now but somehow not getting the reason (or explanation) behind current Lifecycle of Navigation Component. Here are some points that needs clarification.

1. Fragment to Fragment flow

In navigation Component every fragment (or lets say page) is recreated every time it is visited (or revisited). So, when you are at A and go to B, A is destroyed and later when you go back to A (like pressing back button) A is created from stretch.

In a traditional Activity patterns when you go back to A it just goes to onResume as it wasn't destroyed when moving to B. Any reason that this pattern is changed in Navigation Component?

The problem of recreating is when you have a lot of data and it takes time to get redrawn and it feels like app is freezing. An example would be simple HomePage (say Facebook NewsFeed). Preserving data can be handled with ViewModel but drawing of all of the feeds again require time and it will freeze.

There is another problem that recreation generates. Assume this scenario: A has an Collapsing AppBar with a NestedScrollView. User scrolls down and AppBar will collapse and then user moves to a different page B. When he comes back to A it will be redrawn and AppBar is expanded. I am not sure if it is a bug or I should do something to fix it? So any solution here is also welcomed.

2. Activity recreation

If activity is recreated for certain reasons like orientation change, every page in Navigation Component gets recreated until current destination. Although onCreate method of Fragment not onCreateView is getting called, I don't see a point of creating Fragments in Activity recreation. Any explanation would be welcomed.

Upvotes: 20

Views: 8796

Answers (2)

DK96-OS
DK96-OS

Reputation: 56

The way that we use fragments to bridge data and views has changed slightly, and in a good way, when migrating to the Navigation library. It forces us to distinguish between Fragment and View lifecycles.

Pre-navigation: observe LiveData in onCreate() using Fragment's lifecycleScope.

import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
...
import kotlinx.android.synthetic.main.old_fragment.*

class OldFragment : Fragment(R.layout.old_fragment) {
  private val vm by activityViewModels<MainViewModel>()

  override fun onCreate(savedInstanceState: Bundle?) {
    vm.getLiveData().observe(this) { data ->
      oldTextView.text = data.name
    }
  }
}

Navigation: observe LiveData in onViewCreated() using viewLifecycleOwner scope.

...

class NewFragment : Fragment() {
  private val vm by activityViewModels<MainViewModel>()

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    vm.getLiveData().observe(viewLifecycleOwner) { data ->
      oldTextView.text = data.name
    }
  }
}

Key Notes:

  1. Not all Lifecycle Owners are the same. The fragment lifecycle will not execute the observer when the view is recreated (while using Navigation library and navigating up/back).
  2. The viewLifecycleOwner cannot be accessed before the view is created.

Hopefully, this can help prevent replacement of LiveData code as developers migrate to Navigation.

Upvotes: 4

Badhrinath Canessane
Badhrinath Canessane

Reputation: 3518

Navigation component only supports fragment replacement as of now. So you won't be able to add() a fragment as you do it with Manual fragment transaction.

However, if your worry is about re-inflating the layout and re-fetching the data for the fragment, it could be easily resolved with below two methods.

Once the view is created, store it in a variable and use it whenever onCreateView() is called.

private var view: View? = null

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

    if (view == null) {
        view = inflater.inflate(R.layout.fragment_list, container, false)
                //...
    }

    return view

 }

Source: https://twitter.com/ianhlake/status/1103522856535638016

Use ViewModel with the Fragment and hold the data required as a member variable. By this way, the data is not cleared when you replace the associated fragment. The ViewModel gets cleared only on onDestroy() of the fragment, which will only happen when you destroy the parent activity. https://developer.android.com/images/topic/libraries/architecture/viewmodel-lifecycle.png

Upvotes: 14

Related Questions