ContentProvider applyBatch正在阻止UI线程

时间:2017-04-26 12:01:20

标签: android multithreading sqlite android-contentprovider

我已经在SQLite数据库上使用了applyBatch进行插入,更新和删除操作,首次安装app和定期同步的条目超过2000个,由于数据库应用程序上的大量操作得到停止响应。 applyBatch大约需要30-40秒才能完成。

我见过解决方案 来自Insertion of thousands of contact entries using applyBatch is slow的ContentResolver.bulkInsert(Uri url,ContentValues []值)

但它仅用于插入操作,我有查询插入,更新和删除的组合。

我也尝试使用AsyncTask

private class InsertTask extends AsyncTask<ArrayList<ContentProviderOperation>, Integer, Void> {

    @Override
    protected Void doInBackground(ArrayList<ContentProviderOperation>... params) {
        try {

            providerClient.applyBatch(params[0]);

        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);

    }
}

谢谢。

2 个答案:

答案 0 :(得分:2)

申请批次

通常,批处理作业将在一个跨越所有操作的事务中执行。但是如果你的工作包含很多操作,那么事务可能会持续很长时间,并且可能阻止其他任务被执行。

  

使用批量操作的另一面是大批量可能   长时间锁定数据库阻止其他应用程序   从访问数据和可能导致ANR(“应用程序不   回应“对话框。”

为避免数据库的此类锁定,请确保在批次中插入“屈服点”

屈服点:

产量点向内容提供者指示在执行下一个操作之前,它可以提交已经进行的更改,产生其他请求,打开另一个事务并继续处理操作。屈服点不会自动提交事务,但只有在数据库上有另一个请求时才会提交。

  

因此,您应该在开头设置 withYieldAllowed()   每个业务块。

希望它会对你有帮助!

答案 1 :(得分:0)

这里我回复了我自己的问题,问题是由于每个条目在同一个网址上的许多notifyChange()请求,我使用下面的代码推迟了通知

首先覆盖applyBatch函数

private boolean applyingBatch = false;
private List<Uri> delayedNotifications;

@NonNull
@Override
public ContentProviderResult[] applyBatch(@NonNull ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {

    final SQLiteDatabase db = dbHelper.getWritableDatabase();
    db.beginTransaction();
    try {
        applyingBatch = true;
        final int numOperations = operations.size();
        final ContentProviderResult[] results = new ContentProviderResult[numOperations];
        for (int i = 0; i < numOperations; i++) {
            results[i] = operations.get(i).apply(this, results, i);
        }
        db.setTransactionSuccessful();

        applyingBatch = false;

        /*
        *
        * Notify to all URL where change it made
        * */
        synchronized (delayedNotifications) {
            for (Uri uri : delayedNotifications) {
                getContext().getContentResolver().notifyChange(uri, null);
            }
        }
        return results;
    } finally {
        applyingBatch = false;
        db.endTransaction();
    }

}

然后检查批处理操作进度是否存储延迟通知,否则发送通知

 protected void sendNotification(Uri uri) {
    if (applyingBatch) {
        if (delayedNotifications == null) {
            delayedNotifications = new ArrayList<Uri>();
        }
        synchronized (delayedNotifications) {
            if (!delayedNotifications.contains(uri)) {
                delayedNotifications.add(uri);
                LogUtil.debug("ProcessExeCheck  added " + uri);
            }
        }
    } else {
        getContext().getContentResolver().notifyChange(uri, null);
    }
}

检查插入,更新和删除的通知

 @Override
public Uri insert(Uri uri, ContentValues values) {
    Uri result;
    long rawId;
    switch (URI_MATCHER.match(uri)) {

        case ALL_LIST:
            rawId = dbHelper.getWritableDatabase().insert(Table.TABLE_NAME, null, values);
            result = Station.getUriById(rawId);

        default:
            throw new IllegalArgumentException("Uri " + uri + " is not supported");
    }


    sendNotification(LIST.CONTENT_URI);
    return result;
}