Global Loader (LoaderManager) for reuse in multiple Activities / Fragments

余生颓废 提交于 2020-01-01 07:42:04

问题


What I would like to achieve:

I have two different fragments. I would like them both to show the same data in two forms (in a list and on a map). I would like them to share one Loader (AsyncTaskLoader in particular). Everything works fine, but the Loader isn't re-used. Another one is created and the data is loaded twice.

What I do:

In the Fragments I use LoaderManager lm = getActivity().getSupportLoaderManager(); In both of them I implement LoaderCallbacks<ArrayList<Item>> and the required methods. In both I use lm.initLoader(0, args, this);.

But when I output the lm.toString() it appears that these are two different Loaders. And the data is downloaded twice.

How to re-connect to the same Loader from a different Activity/Fragment than the one it was started in?

It should be possible since the context is attached to the Loader anyway on every onCreate(), e.g. on configuration change.


回答1:


How to re-connect to the same Loader from a different Activity/Fragment than the one it was started in?

You should not reuse Loaders that are being managed by a LoaderManager instance across multiple Activitys and Fragments.

The LoaderManager will start/stop those Loaders with respect to the Activity/Fragment lifecycle, so there is no way of guaranteeing that those Loaders will exist once you are in another Activity.

From the documentation:

LoaderManager.LoaderCallbacks is a callback interface that lets a client interact with the LoaderManager.

Loaders, in particular CursorLoader, are expected to retain their data after being stopped. This allows applications to keep their data across the activity or fragment's onStop() and onStart() methods, so that when users return to an application, they don't have to wait for the data to reload. You use the LoaderManager.LoaderCallbacks methods when to know when to create a new loader, and to tell the application when it is time to stop using a loader's data.

In other words, it is often the case that your Loaders will be specific to some Activity (or Fragment). When you have your Activity implement the LoaderManager.LoaderCallbacks interface, your Activity is given type LoaderManager.LoaderCallbacks. Each time you call initLoader(int ID, Bundle args, LoaderCallbacks<D> callback), the LoaderManager either creates or reuses a Loader that is specific to some instance of the LoaderManager.LoaderCallbacks interface (which in this case is an instance of your Activity). This essentially binds your Activity with a Loader, and its callback methods will be called as the loader state changes.

That being said, unless you can find a way to have your two separate Activitys share the same callback methods, I doubt there is a clean way to do this (i.e. having an Activity and a Fragment share the same callbacks sounds like it would be tricky, if not impossible). I wouldn't worry about it too much though. In all of the sample code I have ever seen, I've never seen two Activitys and/or Fragments share the same callback methods. Further, given that Activitys and Fragments are both supposed to be designed for reuse, sharing Loaders in this way just doesn't seem like something that would be encouraged.




回答2:


Yes. It worked for me. I have 3 different Fragments in a Navigation Drawer where the same data is populated in different ListViews. (All Fragments are a part of the SAME Activity).

My AsyncTaskLoader:

public class MyTaskLoader extends AsyncTaskLoader<HashMap<String, Integer>> {

public MyTaskLoader(Context context) {
    super(context);
}

@Override
public HashMap<String, Integer> loadInBackground() {
...
return hashMap;
}

...
}

Use the Same Loader Id in all Fragments.

Fragment1:

public class Fragment1 extends BaseFragment implements LoaderManager.LoaderCallbacks<HashMap<String, Integer>> {
@Override
public void onCreate(Bundle savedInstanceState) {

//initialize adapter

getActivity().getSupportLoaderManager().initLoader(0, null, this);

}

@Override
public Loader<HashMap<String, Integer>> onCreateLoader(int arg0, Bundle arg1) {
    // TODO Auto-generated method stub

    return new MyTaskLoader(getActivity());
}

@Override
public void onLoadFinished(Loader<HashMap<String, Integer>> arg0,
        HashMap<String, Integer> data) {
    // TODO Auto-generated method stub

    listAdapter.setData(data.keySet());

}

@Override
public void onLoaderReset(Loader<HashMap<String, Integer>> arg0) {
    // TODO Auto-generated method stub

    listAdapter.setData(null);
}
}

Use the same Id for Fragment2:

public class Fragment2 extends BaseFragment implements LoaderManager.LoaderCallbacks<HashMap<String, Integer>> {
@Override
public void onCreate(Bundle savedInstanceState) {

//initialize adapter

getActivity().getSupportLoaderManager().initLoader(0, null, this);

}

@Override
public Loader<HashMap<String, Integer>> onCreateLoader(int arg0, Bundle arg1) {
    // TODO Auto-generated method stub

    return new MyTaskLoader(getActivity());
}

@Override
public void onLoadFinished(Loader<HashMap<String, Integer>> arg0,
        HashMap<String, Integer> data) {
    // TODO Auto-generated method stub

    listAdapter.setData(data.keySet());

}

@Override
public void onLoaderReset(Loader<HashMap<String, Integer>> arg0) {
    // TODO Auto-generated method stub

    listAdapter.setData(null);
}
}

The adapter should be initialized before initializing the loader. Works so far. But, is this the right way? Is there a better method for using a common loader for multiple Fragments?




回答3:


I'm not quite sure what you're trying to archieve after going through the discussions. But there is an application.registerActivityLifecycleCallbacks() method, which accept global activity lifecycle listeners (like onActivityCreated()).




回答4:


I think you'll have the desired behavior if you use the same Loader ID across your different Fragments and Activities. Make sure the loader ID are unique to the data to load though. PhotosLoader and VideoLoader shouldn't have the same id for example.



来源:https://stackoverflow.com/questions/10045543/global-loader-loadermanager-for-reuse-in-multiple-activities-fragments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!