Android: SQLite transactions when using ContentResolver Android: SQLite transactions when using ContentResolver sqlite sqlite

Android: SQLite transactions when using ContentResolver


I've seen that in the source code of Google I/O application, they override ContentProvider's applyBatch() method and use transactions inside of it. So, you create a batch of ContentProviderOperation s and then call getContentResolver().applyBatch(uri_authority, batch).

I'm planning to use this approach to see how it works. I'm curious if anyone else has tried it.


It is possible to do transaction based multi table inserts rather cleanly since Android 2.1 by using ContentProviderOperation, as mentioned by kaciula.

When you build the ContentProviderOperation object, you can call .withValueBackReference(fieldName, refNr). When the operation is applied using applyBatch, the result is that the ContentValues object that is supplied with the insert() call will have an integer injected. The integer will be keyed with the fieldName String, and its value is retrieved from the ContentProviderResult of a previously applied ContentProviderOperation, indexed by refNr.

Please refer to the code sample below. In the sample, a row is inserted in table1, and the resulting ID (in this case "1") is then used as a value when inserting the row in table 2. For brevity, the ContentProvider is not connected to a database. In the ContentProvider, there are printouts where it would be suitable to add the transaction handling.

public class BatchTestActivity extends Activity {    /** Called when the activity is first created. */    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        ArrayList<ContentProviderOperation> list = new            ArrayList<ContentProviderOperation>();        list.add(ContentProviderOperation.            newInsert(BatchContentProvider.FIRST_URI).build());        ContentValues cv = new ContentValues();        cv.put("name", "second_name");        cv.put("refId", 23);        // In this example, "refId" in the contentValues will be overwritten by        // the result from the first insert operation, indexed by 0        list.add(ContentProviderOperation.            newInsert(BatchContentProvider.SECOND_URI).            withValues(cv).withValueBackReference("refId", 0).build());        try {            getContentResolver().applyBatch(                BatchContentProvider.AUTHORITY, list);        } catch (RemoteException e) {            e.printStackTrace();        } catch (OperationApplicationException e) {            e.printStackTrace();        }    }}public class BatchContentProvider extends ContentProvider {    private static final String SCHEME = "content://";    public static final String AUTHORITY = "com.test.batch";    public static final Uri FIRST_URI =        Uri.parse(SCHEME + AUTHORITY + "/" + "table1");    public static final Uri SECOND_URI =        Uri.parse(SCHEME + AUTHORITY + "/" + "table2");    public ContentProviderResult[] applyBatch(        ArrayList<ContentProviderOperation> operations)            throws OperationApplicationException {        System.out.println("starting transaction");        ContentProviderResult[] result;        try {            result = super.applyBatch(operations);        } catch (OperationApplicationException e) {            System.out.println("aborting transaction");            throw e;        }        System.out.println("ending transaction");        return result;    }    public Uri insert(Uri uri, ContentValues values) {        // this printout will have a proper value when        // the second operation is applied        System.out.println("" + values);        return ContentUris.withAppendedId(uri, 1);    }    // other overrides omitted for brevity}


All right - so this does not dingle aimlessly: the only way I can think of is to code startTransaction and endTransaction as URL-based query requests. Something like ContentResolver.query(START_TRANSACTION, null, null, null, null). Then in ContentProvider#query based on the registered URL call start or end transaction