Каковы преимущества CursorLoaders?

я использую Cursors экстенсивно в моем приложении, чтобы загружать и иногда записывать информацию из и в базу данных. Я видел, что Honeycomb и пакет совместимости имеют новый Loader классы, предназначенные для помощи в загрузке данных "хорошим" способом.

по сути, эти новые классы (в частности CursorLoader) значительно лучше, чем предыдущие методы управления данными? В чем польза CursorLoader более управляемым Cursors например?

и я использую ContentProvider для работы с данными, что, очевидно, занимает Uris но как это связано с initLoader() способ? Должен ли я настроить каждый из моих Fragments использовать погрузчики индивидуально? И насколько уникальным должен быть id для каждого загрузчика, над областью моего приложения или только фрагмент? Есть ли простой способ просто передать Uri к CursorLoader для запроса моих данных?

все, что я вижу на данный момент, это то, что загрузчики добавляют ненужный дополнительный шаг к получению моих данных в мое приложение, поэтому кто-нибудь объяснит мне их лучше?

2 ответов


есть два ключевых преимущества использования CursorLoader в вашем приложении за Activity.managedQuery():

  1. запрос обрабатывается в фоновом потоке для вас (предоставлен на AsyncTaskLoader), поэтому большие запросы данных не блокировать UI. Это то, что документы рекомендовали вам сделать для себя при использовании простого Cursor, но теперь это делается под капотом.
  2. 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(..) of GlobalCallbacks и начать асинхронную загрузку данных
  • Helper.bundleArgs(..) просто помещает аргументы для запроса в Bundle (напр. столбцы проекции, вроде того, где п.)
  • затем мы устанавливаем Fragment ' s ListAdapter. Курсор все равно будет нулевым в этот момент, поэтому он будет показывать знак загрузки или пустое сообщение до onLoadFinished() называется