Глобальный загрузчик (LoaderManager) для повторного использования в нескольких действиях/фрагментах - программирование
Подтвердить что ты не робот

Глобальный загрузчик (LoaderManager) для повторного использования в нескольких действиях/фрагментах

Что я хотел бы достичь:

У меня есть два разных фрагмента. Я бы хотел, чтобы они оба отображали одни и те же данные в двух формах (в списке и на карте). Я хотел бы, чтобы они делили один загрузчик (в частности, AsyncTaskLoader). Все работает отлично, но Loader не используется повторно. Создается другая, и данные загружаются дважды.

Что я делаю:

В Fragment я использую LoaderManager lm = getActivity().getSupportLoaderManager(); В обоих из них я реализую LoaderCallbacks<ArrayList<Item>> и необходимые методы. В обоих случаях я использую lm.initLoader(0, args, this);.

Но когда я вывожу lm.toString(), кажется, что это два разных загрузчика. И данные загружаются дважды.

Как повторно подключиться к одному загрузчику из другого Activity/Fragment, чем тот, в котором он был запущен?

Это должно быть возможно, поскольку контекст привязан к загрузчику в любом случае на каждом onCreate(), например. при изменении конфигурации.

4b9b3361

Ответ 1

Как повторно подключиться к одному загрузчику из другого Activity/Fragment, чем тот, в котором он был запущен?

Вы не должны повторно использовать Loader, которые управляются экземпляром LoaderManager через несколько Activity и Fragment s.

LoaderManager запустит/остановит те Loader по отношению к жизненному циклу Activity/Fragment, поэтому нет способа гарантировать, что те Loader будут существовать, когда вы находитесь в другом Activity.

Из документации:

LoaderManager.LoaderCallbacks - это интерфейс обратного вызова, который позволяет клиент взаимодействует с LoaderManager.

Ожидается, что загрузчики, в частности CursorLoader, сохранят свои данные после остановки. Это позволяет приложениям сохранять свои данные через действия или фрагменты onStop() и onStart(), поэтому что, когда пользователи возвращаются в приложение, им не нужно ждать данные для перезагрузки. Вы используете методы LoaderManager.LoaderCallbacks когда нужно знать, когда нужно создать новый загрузчик, и сообщить приложение когда пришло время прекратить использование данных загрузчика.

Другими словами, часто бывает, что ваш Loader будет специфичен для некоторых видов деятельности (или фрагмента). Когда ваш Activity реализует интерфейс LoaderManager.LoaderCallbacks, вашей Деятельности присваивается тип LoaderManager.LoaderCallbacks. Каждый раз, когда вы вызываете initLoader(int ID, Bundle args, LoaderCallbacks<D> callback), LoaderManager создает или повторно использует Loader, специфичный для какого-либо экземпляра интерфейса LoaderManager.LoaderCallbacks (который в этом случае является экземпляром вашей Activity). Это по существу связывает вашу активность с загрузчиком, и ее методы обратного вызова будут вызваны, когда изменяется состояние загрузчика.

Если вы не можете найти способ, чтобы ваши две отдельные действия использовали одни и те же методы обратного вызова, я сомневаюсь, что есть чистый способ сделать это (то есть, если у Activity и Fragment есть такие же обратные вызовы, как это было бы сложно, если не невозможно). Я бы не стал беспокоиться об этом слишком много. Во всем примере кода, который я когда-либо видел, я никогда не видел, чтобы две операции и/или Фрагменты использовали одни и те же методы обратного вызова. Кроме того, учитывая, что Activity и Fragment оба должны быть предназначены для повторного использования, совместное использование Loader таким образом просто не похоже на то, что можно было бы поощрять.

Ответ 2

Да. Это сработало для меня. У меня есть 3 разных фрагмента в навигационном ящике, где одни и те же данные заполняются в разных списках ListView. (Все фрагменты являются частью ТОЧНОЙ деятельности).

My AsyncTaskLoader:

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

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

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

...
}

Используйте одинаковый идентификатор загрузчика во всех фрагментах.

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);
}
}

Используйте тот же идентификатор для фрагмента2:

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);
}
}

Адаптер должен быть инициализирован перед инициализацией загрузчика. Работает до сих пор. Но правильно ли это? Есть ли лучший метод для использования обычного загрузчика для нескольких фрагментов?

Ответ 3

Я не совсем уверен, что вы пытаетесь архивировать после обсуждения. Но существует метод application.registerActivityLifecycleCallbacks(), который принимает слушателей жизненного цикла глобальной активности (например, onActivityCreated()).

Ответ 4

Я думаю, что у вас будет желаемое поведение, если вы используете один и тот же идентификатор загрузчика в разных фрагментах и ​​действиях. Убедитесь, что идентификатор загрузчика уникален для данных, которые нужно загрузить. PhotosLoader и VideoLoader не должны иметь одинаковый идентификатор, например.