6

我有一个内容提供者、一个内容解析器和一个游标加载器。加载器用于间接填充列表视图(即不是简单的游标适配器,而是数组适配器,因为我需要使用游标的结果来收集其他数据)。

当我更改基础数据时,列表视图不会重新填充,因为onLoadFinished(Loader<Cursor>, Cursor)不会调用回调。

正如我在写这篇文章时所建议的那样,关于这个问题有很多问题。例如 CursorLoader 在数据更改后不更新

所有的问题都指出了两件事:

  • 在您的内容提供者 query() 方法中,您需要告诉光标有关通知 a'la

c.setNotificationUri(getContext().getContentResolver(), uri);

  • 在您的内容提供商插入/更新/删除方法中,您需要通知 URI:

getContext().getContentResolver().notifyChange(uri, null);

我正在做那些事情。

我也没有关闭我返回的任何游标。

请注意,我的内容提供者存在于一个单独的应用程序中(将其视为内容提供者应用程序 - 没有启动器主要活动)。com.example.provider APK,com.example.app 通过 content://com.example.provider/table URI 等调用(在内容解析器中)。内容解析器(dbhelper)位于库项目中(com.example.appdb),活动链接。(这样,多个项目可以通过链接使用dbhelper,所有内容提供程序通过单个APK安装)

我已经在加载器管理器中打开了调试,并且可以看到我在数据更改后强制刷新的位置(即加载器被重新启动并且之前被标记为非活动),但是没有任何说明会自动发生任何事情——而是响应我的力量刷新。

任何想法为什么我的装载机没有被刷新?

- 编辑 -

加载器创建:

Log.d(TAG, "onCreateLoader ID: " + loaderID);
// typically a switch on the loader ID, and then 
return dbHelper.getfoo()

其中 getfoo() 通过以下方式返回游标加载器:

return new CursorLoader(context, FOO_URI, foo_Fields, foo_query, foo_argArray, foo_sort );

Loader Finish 获取光标并填充一个表(并进行一些处理)——那里没什么特别的。

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    Log.d(TAG, "onLoadFinished id: " + loader.getId());
    // switch on loader ID .. 
    FillTable(cursor, (FooAdapter) foo_info.listview.getAdapter();

Loader Reset 清除表。

public void onLoaderReset(Loader<Cursor> loader) {
    Log.d(TAG, "onLoaderReset id: " + loader.getId());
    // normally a switch on loader ID
    ((FooAdapter)foo_info.listview.getAdapter()).clear();

内容提供者会:

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    Cursor cursor;
    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

        SQLiteDatabase db = dbHelper.getReadableDatabase();

        switch (sUriMatcher.match(uri)) {
        case FOO:
            qb.setTables(FOO);
            qb.setProjectionMap(FooProjectionMap);
            break; 
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
        }

        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);

        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
}

然后插入/更新类似:

public Uri insert(Uri uri, ContentValues initialValues) {
    ContentValues values;
    if (initialValues != null) {
        values = new ContentValues(initialValues);
    } else {
        values = new ContentValues();
    }

    String tableName;
    Uri contentUri;

    switch (sUriMatcher.match(uri)) {
    case FOO:
        tableName = FOOTABLE;
        contentUri = FOO_URI;
        break;

    default:
        throw new IllegalArgumentException("Unknown URI " + uri);
    }

    SQLiteDatabase db = dbHelper.getWritableDatabase();
    long rowId = db.insert(tableName, null, values);
    if (rowId > 0) {
        Uri objUri = ContentUris.withAppendedId(contentUri, rowId);
        getContext().getContentResolver().notifyChange(objUri, null);
        return objUri;
    }

    throw new SQLException("Failed to insert row into " + uri);
}
4

3 回答 3

2

So, for anyone who looks this up and has this problem:

Make certain that the URI you register the cursor on, and the URI you notify the cursor on are the same.

In my case, I was using a different URI to query than was used in other code that modified the underlying table. There wasn't an easy fix to make notification work, so I kept resetting the loader in OnResume() as the solution.

于 2013-12-04T19:49:23.107 回答
2

我看到您没有在 onLoadFinished 和 onLoaderReset 中调用 swapCursor 或 changeCursor。您需要这样做,以便您的适配器访问加载到新游标中的数据。

在 onLoadFinished 中,调用类似:

mAdapter.swapCursor(cursor)

在 onLoaderReset 中,调用它来删除对旧游标的引用:

mAdapter.swapCursor(null)

mAdapter 是您的 listView 的适配器。

更多信息:http: //developer.android.com/guide/components/loaders.html#onLoadFinished

于 2013-06-18T20:55:57.323 回答
1

这不是对这个特定问题的直接答案,但可能会帮助处于类似情况的其他人。就我而言,我有一个连接,即使我在投影和查询中使用了完整的 tablename.columnname。无论如何,它最终使用了错误的 ID 值。因此,请务必检查您的 ContentProvider 或 SQL 语法。

于 2013-12-23T17:42:27.207 回答