James James - 1 month ago 13
Android Question

Proper use of yieldIfContendedSafely() in an Android Multithreaded Application

In my application, I am using an

AsyncTask
to write some data to a database in a transaction. This database is also accessed from the UI thread. While looking through the available database methods, I came across
yieldIfContendedSafely()
. It seems like this method should be used for any cases where a transaction is being made from a separate thread. But there is hardly any documentation on this method other than the following:


Temporarily end the transaction to let other threads run. The transaction is assumed to be successful so far. Do not call
setTransactionSuccessful
before calling this. When this returns a new transaction will have been created but not marked as successful. This assumes that there are no nested transactions (
beginTransaction
has only been called once) and will throw an exception if that is not the case.


Here is how I would assume that you would use this method from a thread:

try {
db.beginTransaction();
//insert some stuff into the database here
...



// is this how you use this method?
boolean yielded = db.yieldIfContendedSafely();
if (yielded) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}



db.setTransactionSuccessful();
} catch (SQLException e) {
return false;
} finally {
db.endTransaction();
db.close();
}


Is this the correct way to use this method? Is it alright to use
db.yieldIfContendedSafely()
more than once in the same transaction, in between multiple writes to different tables in the database? Any suggestions?

Answer

Pulling some example code from the Android libraries it seems much simpler to use than that...

This is taken from com.android.providers.calendar.SQLiteContentProvider.java

@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
    int numValues = values.length;
    mDb = mOpenHelper.getWritableDatabase();
    mDb.beginTransactionWithListener(this);
    try {
        for (int i = 0; i < numValues; i++) {
            Uri result = insertInTransaction(uri, values[i]);
            if (result != null) {
                mNotifyChange = true;
            }
            mDb.yieldIfContendedSafely();
        }
        mDb.setTransactionSuccessful();
    } finally {
        mDb.endTransaction();
    }

    onEndTransaction();
    return numValues;
}

Also looking into the source code for the function itself, it seems that, if yielded, the call will defer execution of your thread for a short period in any case.