Passing Context to ArrayAdapter inside Fragment with setRetainInstance(true) will cause leak?
Solution 1
The Fragment
will be retained (and thus won't be garbage collected). The Fragment
will hold a reference to the adapter, and the adapter holds a reference to the activity Context
, so yes, I believe this will cause a memory leak.
A very simple solution would be to pass getActivity().getApplicationContext()
to the adapter constructor instead.
Solution 2
Depending on what you are using the activity context for it may be possible to use the application context instead, but there are some circumstances where you may still require the activity context. You cannot, for instance, do a findViewById or display a toast/dialog with an application context.
If you must use the activity context, then I would add a method to your adapter for setting the context so you can set it (the context) to null on detach, then set it again when your fragment/activity is recreated.
Here's a good summary of the different context types and their capabilities: http://www.doubleencore.com/2013/06/context/
Mayank Mehta
Updated on July 23, 2022Comments
-
Mayank Mehta almost 2 years
I have a ListFragment which would show list of items via an ArrayAdapter, I'm trying to handle configuration change (Device Rotation) I feel passing activity context to Array Adapter might cause Memory Leak when Activity is restarted on rotation and ListFragment adapter is retained because i'm using setRetainInstance(true), can someone tell me if my understanding is true? If so what is the best way to handle this. And yes I don't want to null my adapter onDetach and reuse it once Fragment view is re-created.
public class DummyXListFragment extends RoboSherlockListFragment{ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (adapter == null) adapter = new DummyItemAdapter(getActivity(), android.R.layout.simple_list_item_1, list); }
-
Mayank Mehta over 10 yearsBut since Adapter shouldn't live more than activity passing it applicationContext wont cause an issue?
-
Alex Lockwood over 10 yearsThe fragment is retained and therefore outlives the activity. So if the fragment holds a reference to the adapter, it will force the adapter to outlive the activity as well. And if the adapter holds a reference to the activity, that activity will never be reclaimed and a memory leak will occur.
-
Mayank Mehta over 10 yearsYeah that is what is troubling me ... I feel re-creating the adapter is better alternative, what say?
-
Alex Lockwood over 10 yearsI don't see why that should be necessary. Just pass it the application context. There's no reason why the adapter should need to be linked directly to the activity lifecycle if it is only used inside the fragment. :)
-
Mayank Mehta over 10 yearsAs you rightly pointed out it won't make sense to link it with activity lifecycle ..Can you clear this for me: Since Adapter would hold reference to Application Context it would remain in memory as long as Application is alive, right? Thinking on those lines I thought about re-creating the adapter (may be i can live with that as far memory foot print wont cause me an issue)
-
Alex Lockwood over 10 yearsThe application context exists for the entirety of the application's lifetime, so there will be no memory leak. You should only need to create the adapter once when the retained fragment is first created... you definitely don't need to recreate the adapter at any time if you pass it the application context.
-
Martin Marconcini over 10 yearsYou might need an activity context if you plan on doing view inflation (and want to preserve the correct Theme/Style) as correctly pointed by goto10 in his answer below.
-
Alex Lockwood over 10 years@MartínMarconcini Yes, but the array adapter never needs to do this, right?
-
Alex Lockwood over 10 years@MartínMarconcini Oops, I misread your comment. Yes, the array adapter will need to inflate views obviously, so you may need to pass the activity context instead.
-
Martin Marconcini over 10 yearsYep, it's ok if you don't need it, but for adapters with getView methods, you might experience strange behavior if you don't have the right context (happened to me) ;)
-
lilbyrdie about 10 yearsSo it would seem a better solution might be to hold on to a weak reference of the activity in the adapter for inflating purposes and update the reference during onactivitycreated.
-
RoundSparrow hilltx almost 10 yearsI'm not sure I have understood all the options presented in this discussion... but I wanted to share something recently discovered: that a View itself is context ;) you can use view.getContext() - and that way it's going to be routed to whoever was the original source. That way even if multiple Activities share a common ArrayAdapter - the origin of the view will be self context.