Too many content provider operations between yield points解决方法

问题引入:
毋庸置疑,电话本数据库中使用批量操作的方式会大大提高效率,使用方式为:
ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
  .withValue(RawContacts.ACCOUNT_TYPE, null)
  .withValue(RawContacts.ACCOUNT_NAME, null)
.withValue(RawContacts.SOURCE_ID, "1000"+i).build());
ops.add(xxx);
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);

但是,如果批量操作的数据过多,比如多余500条的话,就会出现异常
Too many content provider operations between yield points. The maximum number of operations per yield point is 500

Too many content provider operations between yield points解决方法_第1张图片 

这是电话本数据库抛出来的一个异常,如果某个批量操作长久持有数据库连接,就会抛出这个错误。那么这个长久持有数据库连接的判断条件就是:批量操作的操作数多余500条。
代码:
ContactsProvider \src\com\android\providers\contacts\AbstractContactsProvider.java
01 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
02             throws OperationApplicationException {        
03         int ypCount = 0;
04         int opCount = 0;
05         ContactsTransaction transaction = startTransaction(true);
06         try {
07             final int numOperations = operations.size();
08             final ContentProviderResult[] results = new ContentProviderResult[numOperations];
09             for (int i = 0; i < numOperations; i++) {
10                 if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) {
11                     throw new OperationApplicationException(
12                             "Too many content provider operations between yield points. "
13                                     + "The maximum number of operations per yield point is "
14                                     + MAX_OPERATIONS_PER_YIELD_POINT, ypCount);
15                 }
16                 final ContentProviderOperation operation = operations.get(i);
17
18                 if (i > 0 && operation.isYieldAllowed()) {                    
19                     opCount = 0;
20                     try {
21                         if (yield(transaction)) {
22                             ypCount++;
23                         }
24                     } catch (RuntimeException re) {                        
25                     }
26                 }
27                 results = operation.apply(this, results, i);
28             }
29             transaction.markSuccessful(true);
30             return results;
31         } finally {
32             endTransaction(true);
33         }
34     }
官方解释是:为了避免操作长久占用数据库,确保在批量操作中加入”yield points”
如果操作多余500条而不加入yield points的话,就报错,强制停止这次批量操作。

问题分析:
上面说到官方指出批量操作需要加入yield points,那么代码中如何体现的呢?还是上面的applyBatch方法
Too many content provider operations between yield points解决方法_第2张图片 

看到operation.isYieldAllowed()没有,就是这里。如果操作支持yield points的话,就会进入这个if条件
在这个if里面会吧opCount=0;而这个opCount正是上面抛出异常的判断条件。

问题解决:
那既然知道了原因,那就好修改了。在构造批量操作的时候加入yield points。如下:
ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
  .withValue(RawContacts.ACCOUNT_TYPE, null)
  .withValue(RawContacts.ACCOUNT_NAME, null)
  .withValue(RawContacts.SOURCE_ID, "1000"+i)
.withYieldAllowed(true).build());


参考网址:
http://blog.sina.com.cn/s/blog_6dc1188a010133ip.html

你可能感兴趣的:(Too many content provider operations between yield points解决方法)