Каковы преимущества CursorLoaders?
я использую Cursors экстенсивно в моем приложении, чтобы загружать и иногда записывать информацию из и в базу данных. Я видел, что Honeycomb и пакет совместимости имеют новый Loader классы, предназначенные для помощи в загрузке данных "хорошим" способом.
по сути, эти новые классы (в частности CursorLoader) значительно лучше, чем предыдущие методы управления данными? В чем польза CursorLoader более управляемым Cursors например?
и я использую ContentProvider для работы с данными, что, очевидно, занимает Uris но как это связано с initLoader() способ? Должен ли я настроить каждый из моих Fragments использовать погрузчики индивидуально? И насколько уникальным должен быть id для каждого загрузчика, над областью моего приложения или только фрагмент? Есть ли простой способ просто передать Uri к CursorLoader для запроса моих данных?
все, что я вижу на данный момент, это то, что загрузчики добавляют ненужный дополнительный шаг к получению моих данных в мое приложение, поэтому кто-нибудь объяснит мне их лучше?
2 ответов
есть два ключевых преимущества использования CursorLoader в вашем приложении за Activity.managedQuery():
- запрос обрабатывается в фоновом потоке для вас (предоставлен на
AsyncTaskLoader), поэтому большие запросы данных не блокировать UI. Это то, что документы рекомендовали вам сделать для себя при использовании простогоCursor, но теперь это делается под капотом. -
CursorLoaderавтоматическое обновление. В дополнение к выполнению начального запроса,CursorLoaderРегистрацияContentObserverс помощью запрошенного набора данных и вызововforceLoad()на себя, когда набор данных изменений. Это приводит к получению асинхронных обратных вызовов в любое время изменения данных для обновления представления.
каждого Loader экземпляр также обрабатывается через единственное число LoaderManager, поэтому вам все равно не нужно управлять курсором напрямую, и теперь соединение может сохраняться даже за пределами одного Activity. LoaderManager.initLoader() и LoaderManager.restartLoader() позволяет вам повторно подключиться к существующему Loader уже настроен для ваш запрос и, в некоторых случаях, мгновенно получить последние данные, если он доступен.
код Activity или Fragment скорее всего теперь реализуют LoaderManager.Callback интерфейс. Зову initLoader() в результате onCreateLoader() метод, где вы будете строить запрос и новый CursorLoader например, в случае необходимости. The onLoadFinished() метод будет уволен каждый раз, когда новые данные доступны, и будет включать в себя последние Cursor для вас, чтобы прикрепить к представлению или иным образом повторить через.
кроме того, есть довольно хороший пример всего этого фитинга вместе на LoaderManager страница документации класса :
http://developer.android.com/reference/android/app/LoaderManager.html
надеюсь, что это поможет!
если кто-то окажется в подобной ситуации, вот что я сделал:
- создать класс, который реализует
LoaderCallbacksи ручками все запросы, которые вам понадобятся. - поставьте это с
ContextиAdapterв вопрос. - создайте уникальные идентификаторы для каждого запроса ,который вы будете использовать (если вы используете
UriMatcher, могли бы также использовать те же самые) - сделайте удобный метод, который передает запросы в пакет требуется для
LoaderCallbacks - это в значительной степени:) я поставил некоторые из моего кода ниже, чтобы показать, что именно я сделал
в своем GlobalCallbacks класс:
public static final String PROJECTION = "projection";
public static final String SELECTION = "select";
public static final String SELECTARGS = "sargs";
public static final String SORT = "sort";
Context mContext;
SimpleCursorAdapter mAdapter;
public GlobalCallbacks(Context context, SimpleCursorAdapter adapter) {
mContext = context;
mAdapter = adapter;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri contentUri = AbsProvider.customIntMatch(id);
if (contentUri != null) {
return new CursorLoader(mContext, contentUri, args.getStringArray(PROJECTION), args.getString(SELECTION),
args.getStringArray(SELECTARGS), args.getString(SORT));
} else return null;
}
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
mAdapter.swapCursor(arg1);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
mAdapter.swapCursor(null);
}
и когда я хотел использовать CursorLoader (Helper.bundleArgs() это метод связывания удобства):
scAdapt = new Adapters.NewIndexedAdapter(mHost, getMenuType(),
null, new String[] { "name" }, new int[] { android.R.id.text1 });
getLoaderManager().initLoader(
GlobalCallbacks.GROUP,
Helper.bundleArgs(new String[] { "_id", "name" }),
new GlobalCallbacks(mHost, scAdapt));
setListAdapter(scAdapt);
и в Helper:
public static Bundle bundleArgs(String[] projection, String selection, String[] selectionArgs) {
Bundle b = new Bundle();
b.putStringArray(GlobalCallbacks.PROJECTION, projection);
b.putString(GlobalCallbacks.SELECTION, selection);
b.putStringArray(GlobalCallbacks.SELECTARGS, selectionArgs);
return b;
}
надеюсь, это поможет кому-то еще:)
редактировать
подробнее тщательно:
- во-первых, адаптер с нулевым
Cursorинициализируется. Мы не поставляем его сCursor, потому чтоGlobalCallbacksдаст адаптеру правильныйCursorнаonLoadFinished(..) - Далее, мы скажем
LoaderManagerмы хотим инициализировать новыйCursorLoader. Мы поставляем новыйGlobalCallbacksэкземпляр (который реализуетLoader.Callbacks), который затем будет контролировать загрузку курсора. Мы должны поставить его с адаптером тоже, так что он может поменять местами в новомCursorпосле его завершения погрузка. В какой-то моментLoaderManager(который встроен в ОС) вызоветonCreateLoader(..)ofGlobalCallbacksи начать асинхронную загрузку данных -
Helper.bundleArgs(..)просто помещает аргументы для запроса вBundle(напр. столбцы проекции, вроде того, где п.) - затем мы устанавливаем
Fragment' sListAdapter. Курсор все равно будет нулевым в этот момент, поэтому он будет показывать знак загрузки или пустое сообщение доonLoadFinished()называется