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对象
当然 你还可以使用熟悉的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 pointswithValueBackReference(String key, int previousResult)
在Android中 创建一个联系人,需要先创建一个Raw Contact,然后再创建其他附件的数据(电话号码、email、地址等)。而后面的操作需要Raw Contact的ID值作为外键。 由于用到了 ContentProviderOperation,第一步Raw Contact的id还没有生成呢。 这个时候就可以使用withValueBackReference 函数来实现该功能了。在withValueBackReference 函数中第一个参数为 本次操作数据字段的名称 ;第二个参数为 需要引用前面某一次操作的序号
注意
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批量操作提升性能的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 内存分析工具MAT的使用
- 下一篇: RecyclerView的优化:Recy