Multiple rows insert with ContentProvider Multiple rows insert with ContentProvider android android

Multiple rows insert with ContentProvider


I have implemented this in my app and here's the gist of the code that I use.

In my content provider, I have overridden the applyBatch() method and it's a very simple method to override:

/** * Performs the work provided in a single transaction */@Overridepublic ContentProviderResult[] applyBatch(        ArrayList<ContentProviderOperation> operations) {    ContentProviderResult[] result = new ContentProviderResult[operations            .size()];    int i = 0;    // Opens the database object in "write" mode.    SQLiteDatabase db = mOpenHelper.getWritableDatabase();    // Begin a transaction    db.beginTransaction();    try {        for (ContentProviderOperation operation : operations) {            // Chain the result for back references            result[i++] = operation.apply(this, result, i);        }        db.setTransactionSuccessful();    } catch (OperationApplicationException e) {        Log.d(TAG, "batch failed: " + e.getLocalizedMessage());    } finally {        db.endTransaction();    }    return result;}

The result is given to the next operation because you want to support back references. When I actually want to change stuff in the database in this single transaction I loop over my content and do stuff like this:

operations.add(ContentProviderOperation                    .newInsert(                            Uri.withAppendedPath(                                    NotePad.Notes.CONTENT_ID_URI_BASE,                                    Long.toString(task.dbId)))                    .withValues(task.toNotesContentValues(0, listDbId))                    .build());// Now the other table, use back reference to the id the note// receivednoteIdIndex = operations.size() - 1;operations.add(ContentProviderOperation                    .newInsert(NotePad.GTasks.CONTENT_URI)                    .withValues(task.toGTasksContentValues(accountName))                    .withValueBackReferences(                            task.toGTasksBackRefContentValues(noteIdIndex))                    .build());

You just need to remember to finish by calling:

provider.applyBatch(operations);

This will perform your stuff in a single transaction and supports backreferences if you need the id from an earlier insert without issue.


On the client side, ContentResolver supports a bulkInsert() method. Those will not necessarily be processed in a single transaction by the ContentProvider, simply because there may not be any transactions performed by the ContentProvider.


Here an example for bulkInsert:

/** * Perform bulkInsert with use of transaction */@Overridepublic int bulkInsert(Uri uri, ContentValues[] values) {    int uriType = 0;    int insertCount = 0;    try {        uriType = sURIMatcher.match(uri);        SQLiteDatabase sqlDB = dbHelper.getWritableDatabase();        switch (uriType) {        case MEASUREMENTS:            try {                sqlDB.beginTransaction();                for (ContentValues value : values) {                    long id = sqlDB.insert(Tab_Measurements.TABLE_NAME, null, value);                    if (id > 0)                        insertCount++;                }                sqlDB.setTransactionSuccessful();            } catch (Exception e) {                // Your error handling            } finally {                sqlDB.endTransaction();            }            break;        default:            throw new IllegalArgumentException("Unknown URI: " + uri);        }        // getContext().getContentResolver().notifyChange(uri, null);    } catch (Exception e) {      // Your error handling    }    return insertCount;}

And in your code something like:

/** * Inserts new measurement information. *  * @param ArrayList of measurements * @return number of inserted entries */public static long bulkInsertEntries(ArrayList<Item_Measurement> readings) {    // insert only if data is set correctly    if (readings.size() == 0)        return 0;    long insertCount = 0;    try {        // insert new entries        // ArrayList<ContentValues> valueList = new ArrayList<ContentValues>();        ContentValues[] valueList = new ContentValues[readings.size()];        int i = 0;        for (Item_Measurement reading : readings) {            ContentValues values = new ContentValues();            values.put(COL_TIME_READING, reading.getTimeReading());                            // ...            valueList[i++] = values;        }        // returns ID        insertCount = ContentProviderOwn.getAppContext().getContentResolver()                .bulkInsert(ContentProviderOwn.MEASUREMENTS_URI_BASE, valueList);    } catch (Exception e) {        // Your error handling    }    return insertCount;}