使用 ContentProviderOperation 来提升性能

本文介绍Android系统中ContentProvider批量操作的方法及其优势。通过ContentProviderOperation类实现数据的批量更新、插入和删除,确保数据完整性的同时提升应用性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ContentProviders  是android 系统核心组件之一,ContentProviders 封装了数据的访问接口,其底层数据一般都是保存在数据库中或者保存在云端。

有时候你需要更新多行数据,可以选择调用多次ContentResolver的对应函数,或者 使用批量操作。当然 后者性能会比较好些。

为了使批量更新、插入、删除数据更加方便,android系统引入了 ContentProviderOperation类。

在官方开发文档中推荐使用ContentProviderOperations,有一下原因:

  1. 所有的操作都在一个事务中执行,这样可以保证数据完整性
  2. 由于批量操作在一个事务中执行,只需要打开和关闭一个事务,比多次打开关闭多个事务性能要好些
  3. 使用批量操作和多次单个操作相比,减少了应用和content provider之间的上下文切换,这样也会提升应用的性能,并且减少占用CPU的时间,当然也会减少电量的消耗。


要创建ContentProviderOperation对象,则需要使用 ContentProviderOperation.Builder类,通过调用下面几个静态函数来获取一个Builder 对象:

获取Builder 对象的函数
函数用途
newInsert创建一个用于执行插入操作的Builder
newUpdate创建一个用于执行更新操作的Builder
newDelete创建一个用于执行删除操作的Builder

这个Buidler对象使用了著名的Builder设计模式。

由于Builder对象的函数都返回了自己,所以通过一系列的函数调用即可生成最终的ContentProviderOperation对象。

ArrayList<ContentProviderOperation> ops = 
   new ArrayList<ContentProviderOperation>();
ops.add(
   ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
       .withValue(RawContacts.ACCOUNT_TYPE, "someAccountType")
       .withValue(RawContacts.ACCOUNT_NAME, "someAccountName")
       .withYieldAllowed(true)
       .build());

当然 你还可以使用熟悉的ContentValues对象,对应的函数为withValues(values)。

下表是Builder对象核心函数的介绍:

Builder主要函数介绍
函数用途
withSelection (String selection, String[] selectionArgs)指定需要操作的数据条件。只有在更新、删除操作中有用。
withValue (String key, Object value)定义一列的数据值。只在更新、插入数据中有用。
withValues (ContentValues values)定义多列的数据值。 只在更新、插入数据中有用。

另外注意上面示例代码中是使用ArrayList来保存 ContentProviderOperation操作的。后面在介绍withValueBackReference()函数作用的时候就知道为啥用 有序的ArrayList而不是其他List。

最后通过ContentResolver 的applyBatch()函数来应用批量操作:

try {
   getContentResolver().
      applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
   // do s.th.
} catch (OperationApplicationException e) {
   // do s.th.
}

批量操作很简单,提示性能很容易!

如果您还没有使用ContentProviderOperation,赶紧修改吧!



Read more: http://blog.chengyunfeng.com/?p=517#ixzz3CzcGjshp

### 解决 Android Cursor apply 方法无效或无法使用问题 当遇到 `Cursor` 的 `applyBatch()` 或其他操作方法出现问题时,通常是因为对 `ContentResolver` 和 `Cursor` 使用不当造成的。以下是几种常见原因及其解决方案: #### 1. 确认 API 版本兼容性 不同版本的 Android 对于批量更新的支持有所差异,在较新的 Android 版本中推荐使用 `ContentProviderOperation` 来代替直接调用 `applyBatch()`. 如果应用的目标 SDK 是较高版本,则应考虑采用这种方式[^1]. ```java ArrayList<ContentProviderOperation> operations = new ArrayList<>(); // 构建 ContentProviderOperation 列表... getContentResolver().applyBatch(AUTHORITY, operations); ``` #### 2. 正确处理事务 对于大量数据的操作应该包裹在一个事务内完成,这不仅提高了效率还保证了一致性。 ```java SQLiteDatabase db = dbHelper.getWritableDatabase(); db.beginTransaction(); try { while (cursor.moveToNext()) { // 执行数据库修改语句... } db.setTransactionSuccessful(); } finally { db.endTransaction(); } ``` #### 3. 验证权限设置 确保应用程序具有足够的权限去读写所需的数据源。特别是在 Android 10 及以上版本中由于引入了分区存储机制,需要特别注意外部存储器上的文件访问权限配置[^3]. #### 4. 检查游标的生命周期管理 确保在适当的时候关闭游标以释放资源,并且避免跨线程共享同一个游标实例。如果是在异步任务或其他后台进程中使用游标,请务必遵循最佳实践来管理和传递游标对象。 ```java Cursor cursor = null; try { cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); if(cursor != null && cursor.moveToFirst()){ do{ // 处理每一行记录... }while(cursor.moveToNext()); } }catch(Exception e){ Log.e(TAG,"Error reading from database",e); }finally{ if(cursor!=null&&!cursor.isClosed()) cursor.close(); } ``` 通过上述措施可以有效解决大部分关于 `Cursor.applyBatch()` 不起作用的问题。需要注意的是具体实现细节可能会因项目需求和个人编码习惯而有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值