【问题标题】:ContentProvider applyBatch is blocking UI threadContentProvider applyBatch 正在阻塞 UI 线程
【发布时间】:2017-04-27 17:17:47
【问题描述】:

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

我已经看到了解决方案 ContentResolver.bulkInsert (Uri url, ContentValues[] values) from Insertion of thousands of contact entries using applyBatch is slow

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

我也尝试过使用 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);

    }
}

谢谢。

【问题讨论】:

  • 为什么 AsyncTask 没用?
  • 使用 AsyncTask 后,它仍然会阻塞 UI 线程,并且在某些设备上的应用程序会停止响应
  • 不可能...也许 ContentProvider 上的另一个操作会阻止它(例如:您运行此 AsyncTask,然后(在它结束之前)对它进行查询)
  • 根据 contentProvider 执行每个操作后的行为,它 notifyChange()。是因为这个吗?
  • 是的,这可能是一个原因...修改您的 applyBatch 以在完成之前不执行此操作,当您使用默认实现时可能会很棘手,因为它在内部调用 insert/update/delete

标签: android multithreading sqlite android-contentprovider


【解决方案1】:

批量应用

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

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

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

屈服点:

让出点向内容提供者表明,在执行下一个操作之前,它可以提交已经做出的更改、让与其他请求、打开另一个事务并继续处理操作。屈服点不会自动提交事务,但只有在数据库上有另一个请求等待时。

所以,你应该在开始时设置 withYieldAllowed() 调用 每个操作块。

希望对你有帮助!

【讨论】:

  • 谢谢你的回复,你的意思是我已经添加了像这样的所有操作 ContentProviderOperation operation = ContentProviderOperation .newDelete(operationUri) .withYieldAllowed(true) .build();
【解决方案2】:

我在这里回答我自己的问题,问题是由于每个条目在同一 URL 上的许多 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多