Получение SQLiteCursorLoader для наблюдения за изменениями данных - PullRequest
4 голосов
/ 30 января 2012

Я пытаюсь реализовать DataListFragment с помощью адаптера, который использует загрузчик от Commonsware. Этот загрузчик напрямую использует базу данных SQLite и не требует использования ContentProviders.

Ссылка андроида о загрузчиках: «Пока загрузчики активны, они должны отслеживать источник своих данных и выдавать новые результаты при изменении содержимого».

В моей реализации SQLiteCursor (ниже) этого не происходит. OnLoadFinished() вызывается один раз и все. Предположительно, можно вставлять Loader.onContentChanged() вызовы, когда базовая база данных изменяется, но в целом класс кода базы данных не знает о загрузчиках, поэтому я не уверен в том, как лучше реализовать это.

Есть ли у кого-нибудь совет о том, как сделать загрузчик «осведомленным о данных», или я должен обернуть содержимое базы данных в ContentProvider и использовать вместо него CursorLoader?

import com.commonsware.cwac.loaderex.SQLiteCursorLoader;

public class DataListFragment extends ListFragment implements    LoaderManager.LoaderCallbacks<Cursor>{

protected DataListAdapter  mAdapter;     // This is the Adapter being used to display the list's data.
public SQLiteDatabase      mSqlDb;
private static final int   LOADER_ID = 1;

@Override 
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    int rowlayoutID = getArguments().getInt("rowLayoutID");
    // Create an empty adapter we will use to display the loaded data.
    // We pass 0 to flags, since the Loader will watch for data changes
    mAdapter = new DataListAdapter(getActivity(),rowlayoutID, null , 0);
    setListAdapter(mAdapter);
    // Prepare the loader.  Either re-connect with an existing one,
    // or start a new one.
    LoaderManager lm = getLoaderManager();
    // OnLoadFinished gets called after this, but never again.
    lm.initLoader(LOADER_ID, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    String sql="SELECT * FROM "+TABLE_NAME+";";
    String[] params = null;
    SQLiteCursorLoader CursorLoader = new SQLiteCursorLoader(getActivity(), mSqlDb, sql, params);
    return CursorLoader;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Swap the new cursor in.  (The framework will take care of closing the old cursor once we return.)
    mAdapter.swapCursor(data);
    // The list should now be shown.
    if (isResumed()) { setListShown(true);} 
    else { setListShownNoAnimation(true); }
}
public void onLoaderReset(Loader<Cursor> loader) {
    // This is called when the last Cursor provided to onLoadFinished()
    // above is about to be closed.  We need to make sure we are no
    // longer using it.
    mAdapter.swapCursor(null);
}

1 Ответ

20 голосов
/ 30 января 2012

Документация Loader имеет недостатки.

100% реализаций Loader, встроенных в сам Android, "отслеживают источник своих данных и предоставляют новые результаты при изменении содержимого".Поскольку на данный момент в самой Android имеется только одна Loader реализация, их документация является точной, насколько это возможно.

Однако, цитируя мое обновление книги, которое должно быть выпущено через час или два:

В платформе нет ничего, что требовало бы такого поведения.Более того, в некоторых случаях это явно плохая идея - представьте, что загрузчик загружает данные из Интернета, и ему нужно постоянно опрашивать какой-либо сервер, чтобы найти изменения.

Я планирую надобавив SQLiteCursorLoader, чтобы хотя бы чуть-чуть лучше знать об изменениях в базе данных, если вы маршрутизируете через нее все модификации базы данных.Это также будет иметь ограничения, потому что вы не разделяете Loader объекты между действиями (не говоря уже о том, чтобы иметь доступ к ним из сервисов).

Единственная причина, по которой CursorLoader работает так, как это, - это использованиеContentProvider - одиночный код, который может быть осведомлен обо всех операциях.

В настоящий момент любая часть вашего кода, отвечающая за вставки, обновления и удаления, должна будет либо нажать на SQLiteCursorLoader наплечо и попросите его обновить или уведомить активность об изменении (например, трансляцию с Service), чтобы действие могло коснуться SQLiteCursorLoader на плече.

...