我有一个自定义的 ContentProvider
,它管理对 SQLite 数据库的访问。为了在 ListFragment
中加载数据库表的内容,我将 LoaderManager
与 CursorLoader
和 CursorAdapter
结合使用:
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/