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

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 :
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.
As I said before, if I have my MainFragment with 10 sub fragments, I'll have to declare 11 observers ? Weird
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

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.

Related

Is there any misunderstanding about the onActivityCreated fragment callback?

onActivityCreated seems to mean "This fragment callback is executed just after the activity has been... created... I mean, just after the fragment is correctly attached to the activity. There, you can safely call getActivity, it won't return null, except if the activity is null for some special reason".
However, I've seen that the fragment callback onAttach is called even after OnCreate, it means that the fragment has been attached to the activity, which has been created.
The complete workflow for a fragment (and for a fragment dialog, which is frequently left behind) is: onAttach -> onCreate -> onCreateView -> onActivityCreated. So in each of these 4 methods (perhaps not onAttach I don't know), the activity is normally not null and attached to the fragment.
So my question is: why does the callback onActivityCreated since the activity is, in fact, already created and attached to the fragment 3 callbacks ago???
So basically in onAttach() we get confirmation is that activity is attached to my fragment, I can use getActivity() to fetch things like resources like
getActivity().getResources.getDrawable(R.drawable.abc)
but Suppose if You want to fetch the views inflated in activity's xml like If you want to access
getActivity().findViewById(R.id.Myelement)
You might get null here, so OnActivtyCreated() ensures that activity's view is inflated, You can access activity's views now (Activity's view has been created (onActivityCreated))

What is lifecycle of DialogFragment

I could not find proper lifecycle of android.support.v4.app.DialogFragment by searching on Google. I need this for some implementation. As we know DialogFragment has some methods same like Dialog.
DialogFragment extends Fragment so its lifecycle is same as Fragment. But what about other methods of DialogFragment?
Here is Fragment lifecycle. Can one provide for DialogFragment?
DialogFragment life cycle is similar to the life cycle of fragment:. To test yourself put logs in each of the overrided methods of dialogFragment and then run your code you will understand the working of dialogFragment.
onAttach
onCreate
onCreateDialog
onCreateView
onActivityCreated
onStart
onResume
And as far as finishing or destroying dialogFragment is concerned the lifeCycle is as follows:
onPause
onStop
onDestroyView
onDestroy
onDetach
Also I believe this method will also help you know the lifecycle :
#NonNull
#Override
public Lifecycle getLifecycle() {
return super.getLifecycle();
}
Strange, that if you created an AlertDialog in onCreateDialog(), didn't call onCreateView(), then onViewCreated() wouldn't also call.
See Android DialogFragment onViewCreated not called and OnCreateView not called in a dialogfragment from a fragment.
DialogFragment does various things to keep the fragment's lifecycle
driving it, instead of the Dialog. Note that dialogs are generally
autonomous entities -- they are their own window, receiving their own
input events, and often deciding on their own when to disappear (by
receiving a back key event or the user clicking on a button).
Source :
https://developer.android.com/reference/android/app/DialogFragment#lifecycle

Is there "a fragment finished attaching" event?

The only thing I could find that seemed to be relevant was "onAttachFragment". But when I added debug messages, the order was like this.
onAttachFragment()
end of activity's onCreate()
beginning of the fragment's onAttach()
So, onAttachFragment was called before onAttach. What if I need to do something in the activity after the onAttach has been called for the fragment? This is because the fragment's dependency is injected in onAttach, and I need to call a method of the fragment in the activity, after the fragment's dependency has been injected.
PS: The example I saw was calling AndroidSupportInjection.inject(this) in onAttach() of a fragment, so I followed it. But, perhaps I could call that in onCreate() of the fragment?
There's no way to do that with lifecycle methods apart from using onAttachFragment (I'd say use onAttachFragment but that doesn't work for you) , what you can do is simply devise an interface communication between fragment and activity. Create an interface in your fragment:
interface OnFinishAttachCallback{
void finishedAttached();
}
Create a global variable :
OnFinishAttachCallback callback;
Override (you're already doing this) onAttach:
#Override
public void onAttach(Context context) {
super.onAttach(context);
callback = (OnFinishAttachCallback) context;
}
Make your activity implement the interface and simply call callback.finishedAttached() when you want to indicate to your activity that your fragment is ready.

MVP: Best practice to manage Activities and Fragments

I have an Activity with two Fragments. I decided to have one presenter for each "view". So 1 presenter for the main Activity, 1 for the first fragment, and 1 presenter for the second fragment.
I have uses-cases in which I don't know where which code goes.
The first is where to manage fragments with fragment manager ? Do I have to do calls like "beginTransaction().add" in the activity or in his presenter ?
The second is, when the user tap on a button in the activity, I've to do some things in the current fragment. Do I have to call the presenter of the activity which will call the fragment's method wanted, or directly in the method onClick in the activity I call this fragment's method?
PS: I don't want to use any lib/framework
The first is where to manage fragments with fragment manager ? Do I
have to do calls like "beginTransaction().add" in the activity or in
his presenter ?
Everything that is Android API related should be inside the Activity. So, beginTransaction() is a method of the FragmentManager and this is part of the Android API. The Activity is the contract between your app and the operating system. The presenter should not even know that it is used for an Android app. If you press a button inside the Activity for instance it goes like this:
Inside event handler method which is inside your Activity you do this:
Call activityPresenter.onButtonClicked() and it will call activityView.presentWhatTheButtonClickDid()
The second is, when the user tap on a button in the activity, I've to
do some things in the current fragment. Do I have to call the
presenter of the activity which will call the fragment's method
wanted, or directly in the method onClick in the activity I call this
fragment's method?
You would indirectly call the Fragment method via its presenter.
Inside event handler method which is inside your Activity:
Call activityPresenter.onButtonClicked() and it will call
fragmentPresenter.onButtonClicked() and it will calls
fragmentView.presentResult()
So, as you see the Activitiy's presenter needs to know the Fragment's presenter.
*You should not name your presenters with "activity" or "fragment" in its name to keep things abstract. I merely did this for simplicity.

Meaning of fragment having its own lifecycle

Everywhere it is written that fragments have their own lifecycle . Also fragment life cycle depend on activity's lifecycle.What is the meaning of fragment's own lifecycle if it is dependent on activity's lifecycle?
First of all you need to understand what are lifecycle methods are and when are they called/invoked. Lifecycle methods are basically invoked at the different state of your Activty/Fragment. For example when you first launch your activity the following flow of events/methods are called depending upon the state of your activity. For example : When your activity is first launched OnCreate is called, when your activity is no longer visible then onStop is called. So basically you first need to learn at which state are these different activities called.Below is a great referential flowchart for the same.
Activity lifecycle methods :
Fragment lifecycle methods :
Now, when you create a fragment it is inflated into the activty. And it has its own set of lifecycle events/methods which are called and since the fragment is inflated into the activty when the state of your activity changes it effects the fragment and correspondingly different lifecycle methods of the fragments are called. Below is another pictorial representation of the relation between the lifecycle methods of the activity and the fragment.
Image source : Google Images
The activity lifecycle is fairly simple in comparison to the fragment lolcycle (image from Square's Advocating against Android Fragments)

Categories

Resources