2017-04-26 108 views
0

我已經使用applyBatch對SQLite數據庫進行插入,更新和刪除操作,因爲數據庫操作數量很大,因此首次安裝應用程序和定期同步的條目超過2000個應用程序會停止響應。 applyBatch大約需要30-40秒完成。ContentProvider applyBatch正在阻止UI線程

我見過的解決方案,從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); 

    } 
} 

謝謝。

+0

爲什麼AsyncTask沒有用? – Selvin

+0

使用AsyncTask後,它仍然阻塞UI線程,並在某些設備上的應用程序得到停止響應 –

+1

不可能...也許另一個操作在ContentProvider阻止它(例如:您運行此AsyncTask,然後(在結束之前)您查詢它) – Selvin

回答

2

應用批處理

通常情況下,批作業將在跨越所有操作一個事務執行。但是如果你的工作包含許多操作,事務可能會持續一段時間,並且可能阻止其他任務被執行。

使用批量操作的另一面是,一個大批量可 鎖定數據庫很長時間防止其它應用 訪問數據和潛在地導致ANR次數(「應用程序不 響應」的對話框。)

爲避免此類數據庫鎖定,請確保在批次中插入「屈服點」

屈服點:

屈服點表示的內容提供商執行下一步操作,纔可以提交其他請求已經做出了改變,產量,打開另一個事務並繼續處理業務。屈服點不會自動提交事務,但只有在數據庫上有另一個請求正在等待時。

所以,你應該設置withYieldAllowed()在操作中的每個塊的開始 電話。

希望它會幫助你!

+0

謝謝你的回覆, (true) .build(); –

0

我在這裏回答我的問題,問題是由於在每個條目相同的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); 
    } 
} 

檢查通知在插入,UPD通知吃掉和刪除

@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; 
}