当通过批处理操作插入多行时,Android ContentProvider 会调用 setNotificationUri() 到 CursorAdapter

标签 android sqlite android-contentprovider android-cursor android-cursoradapter

我有一个自定义的 ContentProvider,它管理对 SQLite 数据库的访问。为了在 ListFragment 中加载数据库表的内容,我将 LoaderManagerCursorLoaderCursorAdapter 结合使用:

public class MyListFragment extends ListFragment implements LoaderCallbacks<Cursor> {
    // ...
    CursorAdapter mAdapter;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mAdapter = new CursorAdapter(getActivity(), null, 0);
        setListAdapter(mAdapter);
        getLoaderManager().initLoader(LOADER_ID, null, this);
    }

    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getActivity(), CONTENT_URI, PROJECTION, null, null, null);
    }

    public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
        mAdapter.swapCursor(c);
    }

    public void onLoaderReset(Loader<Cursor> loader) {
        mAdapter.swapCursor(null);
    }
}

SQLite 数据库由后台任务更新,该后台任务从 Web 服务获取大量项目,并通过 ContentProvider 批处理操作将这些项目插入数据库 (ContentResolver#applyBatch())。

即使这是一个批处理操作,ContentProvider#insert() 也会被调用,因为每一行都会被插入到数据库中,并且在当前的实现中,ContentProvider 会调用setNotificationUri() 用于每个插入命令。

结果是 CursorAdapter 接收到突发的通知,导致 UI 更新过于频繁,随之而来的是烦人的闪烁效果。

理想情况下,当批处理操作正在进行时,应该有一种方法只在任何批处理操作结束时而不是每个插入命令时通知 ContentObserver

有人知道这是否可行吗?请注意,我可以更改 ContentProvider 实现并覆盖它的任何方法。

最佳答案

我从 Google 的 I/O 应用程序中找到了一个更简单的解决方案。您只需覆盖 ContentProvider 中的 applyBatch 方法并在一个事务中执行所有操作。在事务提交之前不会发送通知,这会最大限度地减少发送的 ContentProvider 更改通知的数量:

@Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
        throws OperationApplicationException {

    final SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
    db.beginTransaction();
    try {
        final int numOperations = operations.size();
        final ContentProviderResult[] results = new ContentProviderResult[numOperations];
        for (int i = 0; i < numOperations; i++) {
            results[i] = operations.get(i).apply(this, results, i);
        }
        db.setTransactionSuccessful();
        return results;
    } finally {
        db.endTransaction();
    }
}

关于当通过批处理操作插入多行时,Android ContentProvider 会调用 setNotificationUri() 到 CursorAdapter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9801304/

相关文章:

android - 为什么 Dagger 组件必须声明它们的作用域?

c - 使用 C API 插入 SQLite 的最快方法?

android - 为 Android 创建和使用 ContentProvider

java - Android 共享首选项崩溃

android - 将 blob 数据插入 android 上的 sqlite 时出错

iphone - 关于数据驱动的 iPhone 应用程序的建议和技巧

android - 计算过去 60 分钟的所有值

android - 如何处理搜索建议点击项目

android - 在 Android 中将原始资源设置为铃声

java - 如何让 Eula.java 显示 Unicode?