Is there "a fragment finished attaching" event? - android

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.

Related

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 :
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.

Which is the best approach to initialize an Interface. (Activity-Frament)?

I am new to the world of Android Programming,Here is my question.
Suppose I've an Activity named A and a Fragment named F. I know that the interaction between Activity and Fragment should be done through an Interface. I used to set the Interface in the onAttach() of Fragment like this
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mListener = (MyListenerInterface) activity;
}
and now am heard about the Static Factory Method from here.
My question is : Which is the best approach to init. a listener ? onAttach() method or initialize the listener through the static factory method ,like this?.
public static MyFragment newInstance(MyListenerInterface mListener) {
MyFragment f = new MyFragment();
this.mListener = mListener;
...........
return f;
}
I think, it is better to initialize the listener through the static factory method instead of casting from the activity,so we could avoid a null pointer exception.
Yes you do not need to cast anything via factory, but onAttach is better in my opinion because you have less chance of leaking an activity context. Let's say you make an instance with the factory and never use that fragment, it will leak the context of the Activity and there by everything in it. Also don't forget to destroy the interface in the onDetach.
Also you can have many instances of that fragment and with option one, they will all have the same listener, not good.
Also you should make what you could call a BaseActivity, an abstract activity all other extend from and define the interface methods there and you will avoid always casting to a lot of different classes. This will also come in handy if you need to quickly change something in every activity of your app.
First option (Initializing the listener in the OnAttach()) is a better one because
In first option the MyListenerInterface is an non-static variable, so each fragment has its own listener.
Whereas the second option's MyListenerInterface variable is an static that is reference maintained at the class level and common for all the other fragment instances this causes the problem when you need the same fragment in different activity then the listener of one activity will be overrided with another activity.

what is the different between onCreate() and onCreateView() lifecycle methods in Fragment?

I don't know when to use onCreate() or onCreateView().
I have used onCreate() and onCreateView() lifecycle methods.
I think onCreate() for Activity and onCreateView() for Fragment. But I am not sure. Can I use onCreate() LifeCycle method in Fragment? I hope somebody can help me!
onCreate is called on initial creation of the fragment. You do your non graphical initializations here. It finishes even before the layout is inflated and the fragment is visible.
onCreateView is called to inflate the layout of the fragment i.e graphical initialization usually takes place here. It is always called some time after the onCreate method.
Activity lifecycle explained - http://developer.android.com/reference/android/app/Activity.html
Fragment lifecycle explained - http://developer.android.com/guide/components/fragments.html#Creating
Detailed lifecycle diagram - https://github.com/xxv/android-lifecycle
From documents :
onCreate
Called when the activity is starting.
This is where most initialization should go: calling setContentView(int) to inflate the activity's UI, using findViewById(int) to programmatically interact with widgets in the UI, calling managedQuery(android.net.Uri, String[], String, String[], String) to retrieve cursors for data being displayed, etc.
You can call finish() from within this function, in which case onDestroy() will be immediately called without any of the rest of the activity lifecycle (onStart(), onResume(), onPause(), etc) executing.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
Link to documentation of onCreate
onCreateView
Called to have the fragment instantiate its user interface view. This is optional, and non-graphical fragments can return null (which is the default implementation). This will be called between onCreate(Bundle) and onActivityCreated(Bundle).
If you return a View from here, you will later be called in onDestroyView() when the view is being released.
Link to documentation of onCreateView

Reusing Activity and Fragment objects

Is it possible that an Activity or Fragment object can be reused by Android system after onDestroy() is called?
In other words: is every call for onCreate() for Activity object and respectively onAttach() for Fragment object preceded by calling its constructor?
You shouldn't do that. Only framework should call methods like onCreate, onAttach etc..
After onDestroy activity should not be used!
ActvitiyLifecycle
Fragments

Execute public Method of Activity from Fragment

I have a Fragment, which should execute a (public) Method reset() from the Activity in the Fragment it is called from.
I found, for example, this page:
Calling Activity methods from Fragment
The other way there's no problem:
Input_tap Input_tap = (Input_tap) getFragmentManager().findFragmentById(R.id.input);
Input_tap.reset();
Does someone has any idea how to do it the other way?
and: Does the Method has to be public - its a "void" Method?
A Fragment can call getActivity() to retrieve the activity that is hosting it.
If there is only one possible activity that can host the fragment, just cast the Activity to the proper class (e.g., MyActivity) and call a method on it:
((MyActivity)getActivity()).someMethod();
If there might be more than one activity that can host the fragment, you are best served by implementing a common interface on all those activities, so you can cast getActivity()'s result to that interface:
((MyInterface)getActivity()).someMethod();

Categories

Resources