Какова область действия LoaderManager?

При определении Loaders в вашем LoaderManager вы используете уникальные идентификаторы. Я спрашиваю о том, насколько уникальны эти идентификаторы.

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

Бонусные баллы, если вы можете сказать мне, как можно изменить, какой LoaderManager вы используете. Если я хочу, чтобы каждый фрагмент моей активности использовал один и тот же LoaderManager (некоторые из них вытаскивают одни и те же данные и разделяют Loaders, было бы хорошо), возможно ли это?

Ответы

Ответ 1

В настоящее время я переношу свое приложение на пакет совместимости Android (в основном для CursorLoader и Fragments). В настоящее время я пытаюсь разделить CursorLoader между двумя фрагментами, чтобы зарезервировать запрос для моего ContentProvider. Добро пожаловать в мой мир!;)

Простой вариант:

- DummyActivity расширяет FragmentActivity/Log.d(Constants.LOGTAG, "DummyActivity.onCreate" + getSupportLoaderManager(). toString());

- DataFragment extends Fragment реализует LoaderManager.LoaderCallbacks/Log.d(Constants.LOGTAG, "DataFragment.onCreate" + getLoaderManager(). toString());

- ReportFragment extends Fragment реализует LoaderManager.LoaderCallbacks/Log.d(Constants.LOGTAG, "ReportFragment.onCreate" + getLoaderManager(). toString());

DummyActivity инициализирует DataFragment, а позднее создает ReportFragment. Выход logcat показывает разные адреса для каждого LoaderManager. Как первый вывод, у каждого фрагмента есть правильный LoaderManager...

Я буду продолжать и обновлять, если я могу ответить на ваш (наш;)) вопрос. Если вы достигли какого-либо прогресса, пожалуйста, поделитесь своими ценными знаниями.

Update:

Мое предположение заключается в том, что идентификаторы загрузчика связаны только с локальной областью LoaderManager для определенного фрагмента, чтобы связать с несколькими фрагментаторами несколько локальных загрузчиков (так что вы можете вернуть другой загрузчик в onCreateLoader на основе id int arg и вызовы initLoader).

Пока мне удалось "повторно использовать" загрузчик (... или нет):

- Во-первых, я включил отладку LoaderManager с помощью getSupportLoaderManager().enableDebugLogging(true); в методе DummyActivity onCreate.

- Затем я вызвал getActivity().getSupportLoaderManager().initLoader(78, null, this); из методов onCreate как DataFragment, так и ReportFragment.

- DataFragment предоставляет CursorLoader, созданный методом onCreateLoader, через установщик в частном члене mCursorLoader.

- ReportFragment onCreateLoader возвращает DataFragment CursorLoader (после извлечения фрагмента с findFragmentByTag).

Отфильтрованный (и слегка запутанный) вывод журнала:

      DummyApp  D  DummyActivity.onCreate
      DummyApp  D  DataFragment.newInstance
      DummyApp  D  ReportFragment.newInstance
      DummyApp  D  DataFragment.onCreate
 LoaderManager  V  initLoader in LoaderManager{405a19d0 in SpecificAction{4059ee98}}: args=null
      DummyApp  D  DataFragment.onCreateLoader
 LoaderManager  V    Created new loader LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}}
      DummyApp  D  DataFragment.onCreate
      DummyApp  D  DataFragment.onActivityCreated
      DummyApp  D  ReportFragment.onCreate
 LoaderManager  V  initLoader in LoaderManager{405a19d0 in DummyActivity{4059ee98}}: args=null
 LoaderManager  V    Re-using existing loader LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}}
      DummyApp  D  SpecificActionReportFragment.onCreate
      DummyApp  D  SpecificActionReportFragment.onActivityCreated
 LoaderManager  V  Starting in LoaderManager{405a19d0 in DummyActivity{4059ee98}}
 LoaderManager  V    Starting: LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}}
 DummyProvider  D  query called
 DummyProvider  D  […]       
 DummyProvider  D  [end of query]
 LoaderManager  V  onLoadComplete: LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}}
 LoaderManager  V    onLoadFinished in CursorLoader{405a22e0 id=78}: CursorWrapperInner{405afb20}
      DummyApp  D  ReportFragment.onLoadFinished
      DummyApp  D  ReportFragment.displayActionReport
      DummyApp  D  DummyActivity.setReportViewsVisibility
      DummyApp  D  ReportFragment.setSaveReportImageViewVisibility

Два фрагмента добавляются из метода DummyActivity onCreate (отличного от описанного варианта использования, но это ничего не меняет в вопросе, над которым мы работаем). К сожалению, загрузчик переназначен к последнему фрагменту, вызывающему его (здесь ReportFragment)... и DataFragment.onLoadFinished никогда не вызывается. Как следствие, ReportFragment выглядит хорошо, но DataFragment не обновляется, поскольку обновление вызывается из onLoadFinished этого класса.

Я предполагаю, что существует основной незарегистрированный вызов, а затем вызов регистра на CursorLoader.

Продолжение следует...

Ответ 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);
}
}

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