Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

onActivityCreated deprecation : how to add fragments as observers of MainActivity using NavigationComponent

I just saw that onActivityCreated() is going to be deprecated in future. I try to implement LifecycleOwner and LifecycleObserver pattern but I'm not quite sure about what I'm doing here.

I'm using NavigationComponent, which meens :

  • I have a MainActivity
  • I have a MainFragment, instanciated as the home fragment
  • I have multiple fragments that can be accessed from this home fragment

For some reasons I need to know when activity is created from all of these fragments (MainFragment and sub fragments)

From what I've seen until now, I need to :

  • In the MainActivity, getLifecycle().addObserver(new MainFragment()). And do this for all sub fragments (which is verbose for nothing)
  • In fragments, implements LifecycleObserver and
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onCreateEvent() {
    Timber.i("%s MainActivity created", TAG);
}

This seems to work well, but I have some questions :

  1. The syntax addObserver(new MainFragment() disturbs me. It looks like we are creating a new fragment instance, while the fragment is normally instantiated with the navigation defined in the navGraph.
  2. As I said before, if I have my MainFragment with 10 sub fragments, I'll have to declare 11 observers ? Weird
  3. Do I have to clear these observers at some point in the activity lifecycle ?

What is the proper way to implement it ?

EDIT 1: To answer the question why I need to know when the activity is created : I need this because I need to access my MainActivity viewmodel (new ViewModelProvider(requireActivity()).get(ViewModel.class). To call requireActivity() or getActivity() I need to know when the activity is created (was easy with onActivityCreated()). Databinding is implemented with my MainActivity and this viewmodel. The layout of this activity is hosting a loader to show when network requests are performed. I can perform requests from the MainFragment and from the sub fragments. When I perform a request from one of these fragments I need to enable this loader view, and when I got datas back I need to hide this loader. And yes, all these fragments are in the graph

like image 249
Gilles Avatar asked Oct 02 '20 16:10

Gilles


People also ask

Is onActivityCreated deprecated?

Need for onActivityCreated() deprecation In such similar fashion android developers saw the tight coupling of code dependent to the Activity's life cycle. And they decided that it is not a good practice anymore to be dependent on the activity attach to do certain things inside the fragment.

What are the differences between onCreate () onCreateView () and onActivityCreated () in fragments and what would they each be used for?

The onCreate() is called first, for doing any non-graphical initialisations. Next, you can assign and declare any View variables you want to use in onCreateView() . Afterwards, use onActivityCreated() to do any final initialisations you want to do once everything has completed.

What is onActivityCreated in fragment?

onActivityCreated(Bundle) tells the fragment that its activity has completed its own Activity. onCreate() . onViewStateRestored(Bundle) tells the fragment that all of the saved state of its view hierarchy has been restored.

Can we navigate from activity to fragment?

If you want to go back from Activity to Fragment. This is very simple just override onBackPressed() in your activity and call onBackPressed where you want.


1 Answers

You have never needed to wait for onActivityCreated() to call requireActivity() or getActivity() - those are both available as soon as the Fragment is attached to the FragmentManager and hence can be used in onAttach(), onCreate(), onCreateView(), onViewCreated() all before onActivityCreated() is called.

This is one of the reasons why onActivityCreated() was deprecated - it actually has nothing to do with the activity becoming available to the Fragment, nor does it have anything to do with the activity finishing its onCreate() (it, in fact, can be called multiple times - every time the Fragment's view is created, not just once after the first time the Activity finishes onCreate()).

As per the deprecation notice:

use onViewCreated(View, Bundle) for code touching the Fragment's view and onCreate(Bundle) for other initialization.

Those are the recommended replacements, depending on whether the code you had in onActivityCreated() was accessing the Fragment's views or not.

Once you realize that requireActivity() can be called in onAttach(), etc., the rest of the deprecation notice makes more sense:

To get a callback specifically when a Fragment activity's Activity.onCreate(Bundle) is called, register a LifecycleObserver on the Activity's Lifecycle in onAttach(Context), removing it when it receives the Lifecycle.State.CREATED callback.

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    // Register a LifecycleObserver on the Activity's Lifecycle in onAttach()
    requireActivity().getLifecycle().addObserver(this);
}

@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onCreateEvent() {
    // Remove the LifecycleObserver once you get a callback to ON_CREATE
    requireActivity().getLifecycle().removeObserver(this);

    // Then do your logic that specifically needs to wait for the Activity
    // to be created
    Timber.i("%s MainActivity created", TAG);
}

But, as mentioned above, this is not what you should be doing if you are trying to access a ViewModel at the activity level.

like image 188
ianhanniballake Avatar answered Nov 02 '22 23:11

ianhanniballake