欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

ContentProviderOperation批量操作提升性能

发布时间:2025/4/16 57 豆豆
生活随笔 收集整理的这篇文章主要介绍了 ContentProviderOperation批量操作提升性能 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

原文出处:http://blog.csdn.net/imuhao/article/details/52002995

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

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

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

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

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

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

函数说明
newInsert ()创建一个用于执行插入操作的Builder
newUpdate ()创建一个用于执行更新操作的Builder
newDelete()创建一个用于执行删除操作的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对象核心函数

  • withSelection (String selection, String[] selectionArgs)
    指定需要操作的数据条件。只有在更新、删除操作中有用。

  • withValue (String key, Object value)
    定义一列的数据值。只在更新、插入数据中有用。

  • withValues (ContentValues values)
    定义多列的数据值。 只在更新、插入数据中有用

  • withYieldAllowed(boolean)
    批量操作一大堆数据可能会长期锁定数据库,从而阻止其他应用访问该数据库并且有可能会引起ANR(应用无响应)对话框出现。
    为了避免长期锁定数据库,只要在批量操作中添加“yield points”即可。一个yield points告诉Content Provider,在执行下一个操作之前可以先提交当前的数据,然后通知其他应用,如果有其他应用请求数据的话,就先让其他应用操作,等其他应用操作完成后,再继续打开一个事务来执行下一个操作。如果没有其他程序请求数据,则一个yield points不会自动提交事务,而是继续执行下一个批量操作。通常情况下一个同步Adapter应该在开始操作一行原数据之前添加一个yield points

  • withValueBackReference(String key, int previousResult)
    在Android中 创建一个联系人,需要先创建一个Raw Contact,然后再创建其他附件的数据(电话号码、email、地址等)。而后面的操作需要Raw Contact的ID值作为外键。 由于用到了 ContentProviderOperation,第一步Raw Contact的id还没有生成呢。 这个时候就可以使用withValueBackReference 函数来实现该功能了。在withValueBackReference 函数中第一个参数为 本次操作数据字段的名称 ;第二个参数为 需要引用前面某一次操作的序号

ops = new ArrayList<ContentProviderOperation>(); ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI).withValue(RawContacts.ACCOUNT_TYPE, someAccountType).withValue(RawContacts.ACCOUNT_NAME, someAccountName).build()); ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).withValueBackReference(Data.RAW_CONTACT_ID, 0).withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE).withValue(StructuredName.DISPLAY_NAME, displayName).withValue(StructuredName.FAMILY_NAME, lastName).withValue(StructuredName.GIVEN_NAME, firstName).build()); ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).withValueBackReference(Data.RAW_CONTACT_ID, 0).withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE).withValue(Phone.NUMBER, phoneNumber).withValue(Phone.TYPE, Phone.TYPE_HOME).withValue(Phone.LABEL, label).build()); ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI).withValueBackReference(Data.RAW_CONTACT_ID, 0).withValue(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE).withValue(Event.TYPE, Event.TYPE_BIRTHDAY).withValue(Event.START_DATE, dateStr).build()); try {getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (RemoteException e) {// some error handling } catch (OperationApplicationException e) {// some error handling }

注意

ContentProviderOperation是放到一个ArrayList中的,第一个(序号为0)操作创建了一个Row Contact,后续的几个操作分别需要第一个操作返货的ID值,该值对应的数据列名称为Data.RAW_CONTACT_ID,所以

withValueBackReference(Data.RAW_CONTACT_ID, 0)两个参数分别为Data.RAW_CONTACT_ID 和 0

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

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

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

批量添加联系人

public static void batchAddContact(Context context, List<FriendBean> list) throws RemoteException, OperationApplicationException {ArrayList<ContentProviderOperation> ops = new ArrayList<>();int rawContactInsertIndex = 0;for (FriendBean contact : list) {rawContactInsertIndex = ops.size(); // 有了它才能给真正的实现批量添加ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI).withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null).withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).withYieldAllowed(true).build());// 添加姓名ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI).withValueBackReference(ContactsContract.Contacts.Data.RAW_CONTACT_ID,rawContactInsertIndex).withValue(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE).withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName()).withYieldAllowed(true).build());// 添加号码ops.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI).withValueBackReference(ContactsContract.Contacts.Data.RAW_CONTACT_ID,rawContactInsertIndex).withValue(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE).withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, contact.getPhone()).withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE).withValue(ContactsContract.CommonDataKinds.Phone.LABEL, "").withYieldAllowed(true).build());}// 真正添加context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);}

批量删除联系人

public static void batchDeleteContact(Context context, List<FriendBean> list) throws RemoteException, OperationApplicationException {ArrayList<ContentProviderOperation> ops = new ArrayList<>();for (FriendBean contact : list) {String name = contact.getName();//根据姓名求idUri uri = Uri.parse("content://com.android.contacts/raw_contacts");ContentResolver resolver = context.getContentResolver();Cursor cursor = resolver.query(uri, new String[]{ContactsContract.Data._ID},"display_name=?", new String[]{name}, null);if(cursor.moveToFirst()){int id = cursor.getInt(0);//根据id删除data中的相应数据ops.add(ContentProviderOperation.newDelete(uri).withSelection("display_name=?",new String[]{name}).build());uri = Uri.parse("content://com.android.contacts/data");ops.add(ContentProviderOperation.newDelete(uri).withSelection("raw_contact_id=?",new String[]{id + ""}).build());}}context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);}

总结

以上是生活随笔为你收集整理的ContentProviderOperation批量操作提升性能的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。