Is it safe to maintain a strong fragment reference in AsyncTask?

Since it is not recommended to maintain a strong reference to Context in the task (the context can be destroyed while the task is still running, but stored in the memory by this task), I was wondering if the same would apply to Fragments?

Fragments control the link to their activity, and support is maintained through setRetainInstance . Can I assume that, for example, creating a non-static internal AsyncTask in a Fragment is safe from the point of view that you are not at risk of leaking $this ?

+6
source share
2 answers

In general, this is a bad methodology for storing links between threads, and AsyncTask is a bit of a thread.

It's all right if you make sure you play it when you're done with it.

Otherwise, you may get memory leaks.

In this case, this is normal, because your Fragment is in the AsyncTask context. When the task is completed, it will lose this link.

If this was done in Service , that would be a very bad idea.

+6
source

Phoenixblade9's answer is correct, but to make it complete, I would add one thing.

There's a great replacement for AsyncTask - AsyncTaskLoader or Loaders in general. It manages the life cycle according to the context from which it was called (Activity, Fragment), and implements a bunch of listeners to help you separate the logic of the second thread from the ui thread. And this is usually immune to the current context.

And do not worry about the name - it is also useful for saving data.


As promised, I will send my code for AsyncTaskLoader along with several returned objects. The bootloader looks something like this:

 public class ItemsLoader extends AsyncTaskLoader<HashMap<String, Object>>{ HashMap<String, Object> returned; ArrayList<SomeItem> items; Context cxt; public EventsLoader(Context context) { super(context); //here you can initialize your vars and get your context if you need it inside } @Override public HashMap<String, Object> loadInBackground() { returned = getYourData(); return returned; } @Override public void deliverResult(HashMap<String, Object> returned) { if (isReset()) { return; } this.returned = returned; super.deliverResult(returned); } @Override protected void onStartLoading() { if (returned != null) { deliverResult(returned); } if (takeContentChanged() || returned == null) { forceLoad(); } } @Override protected void onStopLoading() { cancelLoad(); } @Override protected void onReset() { super.onReset(); onStopLoading(); returned = null; } 

In the getYourData() function, I get the server code code or another error code and ArrayList<SomeItem> . I can use them in my fragment as follows:

 public class ItemListFragment extends ListFragment implements LoaderCallbacks<HashMap<String, Object>>{ private LoaderManager lm; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); lm = getLoaderManager(); Bundle args = new Bundle(); args.putInt("someId", someId); lm.initLoader(0, args, this); } @Override public Loader<HashMap<String, Object>> onCreateLoader(int arg0, Bundle args) { ItemsLoader loader = new ItemsLoader(getActivity(), args.getInt("someId")); return loader; } @Override public void onLoadFinished(Loader<HashMap<String, Object>> loader, HashMap<String, Object> data) { if(data!=null){ if(data.containsKey("items")){ ArrayList<SomeItem> items = (ArrayList<EventItem>)data.get("items"); } else { //error int error = 0; if(data.containsKey("error")){ error = (Integer) data.get("error"); } } } @Override public void onLoaderReset(Loader<HashMap<String, Object>> arg0) { } 
+2
source

Source: https://habr.com/ru/post/916393/


All Articles