Каковы преимущества 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()
называется