Beste practices with SetRetainInstanceState? - android

I'm currently having issues with fragment lifecycle management.
Should the activity the fragment is hosted in be recreated I have set SetRetainInstanceState(true) to keep the fragment instance alive.
However, this had lead to some strange behaviour regarding my views. Sometimes I get memory leak warnings concerning a few fragment views and nullpointer exceptions to the activity context.
Wanting to make sure the fragment instance is retained properly: what are best practices regarding the retaining of a fragment (what to keep, what to destroy)?

SetRetainInstanceState(true) makes sure Android retains the fragment while the activity is being recreated. Therefore the activity the fragment was first attached to is not longer there after activity recreation and the fragment is attached to a new activity instance.
To make sure this goes well keep the following things in mind:
Do not keep a reference to the attached activity in your fragment unless absolutely necessary. Use the getActivity() method instead which will always return the currently attached fragment (or null if nothing is attached).
If you absolutely have to have a "permanent reference" to the currently attached activity (in which you might want to rethink your design) make sure to update this reference in the onAttach and onDetach methods.
Make sure you retain no object that was initialized using the activity as a context (usually views, adapters and such). To do this, override the Fragments onDestroyView() method that gets called just before activity recreation. Here you can dispose of the views and adapters the fragment still has a active reference to (usually just setting their reference to null should be enough). You can then recreate the fragment's views and adapters using the new context in the onCreateView call.

Related

Android - Do activity realases fragment references when finished?

According to Android Developer site, the correct way of communicating an activity with their fragment is through listeners.
https://developer.android.com/training/basics/fragments/communicating
My question is, this fragment is holding a reference to the activity... when the activity is destroyed, will the fragment manager release the fragment and thus the fragment will be collected and so the activity? or do they hold a strong reference that needs to be nullified too in the Fragment's onDestroy?
The Fragments Lifecycle is bound to the one of the Activity. Imagine an Activity as the Universe and Fragments as Planets / Stars. If the Universe dies, so do the Stars / Planets inside of it. Similarly, if an Activity gets destroyed so do all of it's Fragments.
The official documentation (which you should definitely check out) explains it very well:
A fragment must always be hosted in an activity and the fragment's
lifecycle is directly affected by the host activity's lifecycle. For
example, when the activity is paused, so are all fragments in it, and
when the activity is destroyed, so are all fragments. However, while
an activity is running (it is in the resumed lifecycle state), you can
manipulate each fragment independently, such as add or remove them.
When the activity containing the fragment is destroyed, so is the fragment automatically. Check this out

lateinit property not initialized when Activity is re-created

In my Activity I have a lateinit property called controller that my Fragment uses.
This property is initialized in Activity.onCreate(). My Fragment gets its reference back to my Activity through onAttach(). The Fragment then calls myActivity.controller in Fragment.onCreate().
Normally controller is first initialized in Activity.onCreate(), and after that, the Fragment is added. So this works just fine.
But when my Activity has been killed, it tries to recreate itself and its fragments. This causes Fragment.onCreate() to be called before the initialization took place in Activity.onCreate().
These are the options I see right now:
initialize controller before super.onCreate() (if that's even possible)
move the call to myActivity.controller to a later lifecycle callback, as onViewCreated()
something with ::controller.isInitialized available in Kotlin 1.2
What is my best option here?
By reviewing the Fragment lifecycle, in fact the safest point to do it will be #onActivityCreated(android.os.Bundle).
Even when #onAttach() looks like it is called when the Fragment is attached to the Activity, I'm not sure if this is completely guaranteed, as the old #onAttach(android.app.Activity) is deprecated, and the new #onAttach(android.content.Context) is recommended.
The best way to handle such scenario where an object is used before initialization is by checking with isInitialized() property and then using it.

Holding activity instance in fragment: can it result in a memory leak?

I have an Activity with some Fragments. From each fragment, I need to call aMethod() implemented by the Activity. So, I do something like this:
((MyActivity)getActivity()).aMethod();
I'm referencing the activity many times, so I decided hold a reference to the activity. When fragment is created, I have:
MyActivity act; // this s a fragment's member
//...
act = (MyActivity) getActivity();
I'm wondering if holding that reference could result in a memory leak.
If so, I have thought in two solutions:
act = null; when fragment is destroyed (onDestroy())
Using a WeakReference: act = new WeakReference((MyActivity) getActivity());
Are both valid? Does it make sense?
You don't even need to hold a reference. Just keep using
getActivity()
A fragment lifecycle is joined to that of its activity so you don't need to worry about it.
If you still want to store a reference, a safe bet is to use the WeakReference as you said yourself.
This will make the reference available for garbage collection when needed. Just keep checks for not null before using the reference though.
Nope that's not memory leak.
We are getting instance of Activity from where we can load fragment.
so you also need to pass instance of Activity or As per you already do casting and through getActivity() is correct.
But Remember one thing whenever onPause(), onStop() and onDestroy() called at that time to release instace of Activity otherwise it holds memory and Garbage collector not clear it so in such senario/situations only memory leak occurs.

can we pass the activity handle inside the fragment so as communicate to activity from fragment

i am trying to alter the activity content from fragment. for that i want to pass the activity handle inside fragment and do the required changes.
If i can do that why there is more difficult way of interface etc.
You can call getActivity() from the Fragment.
If you want to get your activity specifically you can cast it
((MyActivity) getActivity()).someMethod()
This will tightly couple your Fragment to your activity and prevent you using the fragment in a different activity easily so be careful.
Also you need to be careful with lifecycles and such as a fragment can become detached from an activity causing a NullPointerException from time to time. So it is recommended to wrap this in a null check

Loaders in fragment - will the fragment leak?

consider this example from the android tutorial,
getLoaderManager().initLoader(0, null, this);
is called onActivityCreated, giving the loaderCursorLoaderListFragment.this instance, as far as i can tell there is no garuantee that the given fragment lifecycle is equal to the Activity hence LoaderManager lifecycle. So, if the fragment is removed while Activity is still living would it not cause a memory leak?
If yes, then how should they correct this example?
Loaders are destroyed and cleaned up when the bound Fragment or Activity destroys. i.e. If you pass Fragment instance to the initLoader(), then the Loader is destroyed when that Fragment instance is destroyed.
Reference:
https://medium.com/google-developers/making-loading-data-on-android-lifecycle-aware-897e12760832#.ai7whgsv4
Loaders don’t stay around forever. They’ll be automatically cleaned up
when the requesting Activity or Fragment is permanently destroyed.
That means no lingering, unnecessary loads.

Categories

Resources