[讨论]Android批量操作电话本数据库引发的问题以及解决方法 ..._Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 2410 | 回复: 0   主题: [讨论]Android批量操作电话本数据库引发的问题以及解决方法 ...        下一篇 
momoda
注册用户
等级:少校
经验:1149
发帖:28
精华:0
注册:2015-7-14
状态:离线
发送短消息息给momoda 加好友    发送短消息息给momoda 发消息
发表于: IP:您无权察看 2015-7-15 14:44:55 | [全部帖] [楼主帖] 楼主

问题引入:
毋庸置疑,电话本数据库中使用批量操作的方式会大大提高效率,使用方式为:

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


这是电话本数据库抛出来的一个异常,如果某个批量操作长久持有数据库连接,就会抛出这个错误。那么这个长久持有数据库连接的判断条件就是:批量操作的操作数多余500条。

代码:

public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
         throws OperationApplicationException {     
           int ypCount = 0;
           int opCount = 0;
           ContactsTransaction transaction = startTransaction(true);
           try {
                     final int numOperations = operations.size();
                     final ContentProviderResult[] results = new ContentProviderResult[numOperations];
                     for (int i = 0; i < numOperations; i++) {
                              if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) {
                                     throw new OperationApplicationException(
                                            "Too many content provider operations between yield points. "
                                                 + "The maximum number of operations per yield point is "
                                                 + MAX_OPERATIONS_PER_YIELD_POINT, ypCount);
                              }
                              final ContentProviderOperation operation = operations.get(i);

                              if (i > 0 && operation.isYieldAllowed()) {             
                                     opCount = 0;
                                     try {
                                               if (yield(transaction)) {
                                                        ypCount++;
                                               }
                                     } catch (RuntimeException re) {                 
                               }
                        }
                        results = operation.apply(this, results, i);
               }
               transaction.markSuccessful(true);
               return results;
     } finally {
         endTransaction(true);
     }
    }
官方解释是:为了避免操作长久占用数据库,确保在批量操作中加入”yield points”
如果操作多余500条而不加入yield points的话,就报错,强制停止这次批量操作。
问题分析:
上面说到官方指出批量操作需要加入yield points,那么代码中如何体现的呢?还是上面的applyBatch方法

看到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());




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论