我有一个自定义的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会为每个insert命令调用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会向CursorAdapter调用setNotificationUri()突发,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9801304/

10-10 20:22