16

Что я хотел бы достичь:Global Loader (LoaderManager) для повторного использования в нескольких Мероприятия/Фрагменты

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

Что я делаю:

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

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

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

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

+0

вы можете объяснить, почему вам нужно ссылаться на «загрузчик» как в «Фрагменте», так и в его родительской «Деятельности»? имейте в виду, что рекомендуется создавать ваши «Фрагменты» для повторного использования ... все может стать довольно беспорядочным, если вы начнете переплетать явное поведение ваших «Активность» и «Фрагмент ... старайтесь выполнять как можно большую работу в каждом классе отдельно, а затем при необходимости применяйте методы обратного вызова «Активность». –

+0

, что, как говорится, я дам вам возможность объяснить ваши рассуждения, прежде чем я начну звучать слишком педантично: P –

+0

О нет, вы неправильно поняли. Это не его родительская деятельность! Это совсем другое занятие. Смысл вопроса остался бы таким же, если бы я спросил о двух фрагментах. ** Как повторно использовать один загрузчик в двух разных фрагментах? ** Просто я использую фрагмент внутри некоторого Activity для списка и MapActivity для карты, я подумал, что, возможно, это имеет значение, но я так не думаю. –

ответ

5

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

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

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

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

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

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

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

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

+1

A-ha! Поэтому он не связан с Activity, а с LoaderCallbacks. Я не думаю, что было бы невозможно написать внешний класс, который расширяет LoaderCallbacks. Спасибо за это! Вы говорите, что это не рекомендуется. Но для меня это идеальный способ использовать одни и те же данные, чтобы показать его пользователю двумя разными способами. В списке и на карте в моем примере. Вам не кажется? Теперь я использую загрузчик для его загрузки, и я пишу его в контекст приложения. Это не идеально, потому что если загрузчик в списке не завершил работу и пользователь переключился на карту, то тот же загрузчик снова запустится. –

+0

«... найти способ, чтобы ваши две отдельные действия использовали одни и те же методы обратного вызова, я сомневаюсь, что есть чистый способ сделать это» - я хотел бы, чтобы кто-то объяснил нам, если это возможно. Из того, что я думаю, это потому, что это LoaderManager, связанный с жизненным циклом Activities/Fragments, а не с LoaderCallbacks. Но, может быть, я ошибаюсь –

+0

Хм ... да, это имеет смысл. Возможно, вы могли бы попробовать, чтобы ваш 'Activity' расширил класс, который реализует' LoaderManager.LoaderCallbacks'. Таким образом, они оба наследуют одни и те же обратные вызовы и, возможно, вы можете повторно использовать Loader таким образом. Я никогда не пытался это сделать ... дайте мне знать, если вы что-то придумаете, и я обновлю свой ответ :). –

0

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

+0

Это старая дискуссия. Этот «повторно используемый загрузчик» оказался совершенно бесполезным, когда я действительно понял шаблон Android для загрузки и кэширования данных (используя ContentProvider и т. Д.). –

1

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

Мой AsyncTaskLoader:

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

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

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

... 
} 

Используйте тот же Loader Id во всех фрагментах.

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

Используйте тот же идентификатор для 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); 
} 
} 

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

+0

Я думаю, что все в порядке - оно работает, потому что вы используете поддержку (common) ActivityLoaderManager плюс один и тот же идентификатор загрузчика, поэтому один и тот же загрузчик просто используется несколько раз. Я не вижу причин, почему все будет не так? И это приятно и просто, не нужно кэшировать или создавать другой набор слушателей-вещателей и управлять ими. – gkee

+0

К сожалению, это не сработало. Загрузчик только воссоздавался в методе onCreate() каждого фрагмента. Данные загружаются каждый раз при создании Фрагмента. – user3316561

0

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

+0

Из-за Firebase? Или я чего-то не хватает? Кстати, эта статья была в этом году: https://medium.com/google-developers/making-loading-data-on-android-lifecycle-aware-897e12760832 –

+0

Я имел в виду Rxjava, но, как правило, погрузчики были в порядке, но там являются лучшими альтернативами. –

Смежные вопросы