Android’s ContentProviderOperation: “withYieldAllowed” explained

Whenever you use a ContentProviderOperation and have to insert, update or delete many records, the method withYieldAllowed() comes in handy.

Normally the batch job would be executed in one transaction that spans all operations. But if your job contains many manipulations, the transaction might last quite a while and it might block other tasks from being executed. This can be an issue, especially if you use standard content providers like ContactsContract or CalendarContract that might be used by many apps and background services (e.g. sync adapters) at the same time.

The method withYieldAllowed() of the nested class ContentproviderOperation.Builder deals with this problem. Alas what this method does is not documented on the class itself. It is documented – just somewhere else :-)

What this method does, can be found within the documentation to ContactsContract's inner class Data:

The flip side of using batched operations is that a large batch may lock up the database for a long time preventing other applications from accessing data and potentially causing ANRs ("Application Not Responding" dialogs.)

To avoid such lockups of the database, make sure to insert "yield points" in the batch. A yield point indicates to the content provider that before executing the next operation it can commit the changes that have already been made, yield to other requests, open another transaction and continue processing operations. A yield point will not automatically commit the transaction, but only if there is another request waiting on the database. Normally a sync adapter should insert a yield point at the beginning of each raw contact operation sequence in the batch.

So whenever you have operations within your batch job that must be executed together but that are independent of the following tasks add a withYieldAllowed() at the beginning of each of these logical blocks. — I edited the previous sentence after amay82 asked the question in the comments below.

Say you add multiple appointments as a sync adapter. In this case you will add an records to events, to instances and probably to reminders. All these must be executed within one transaction for each event. But it is not necessary to execute all events in one transaction. You can sync the other events later on, if something goes awry.

Of course one transaction is faster. So Android will not necessarily commit your transaction at every yield point. Instead it does so only if necessary.

I have filed a bug report asking for an appropriate documentation of this method. Please star the issue so that it get's fixed faster.

What's your take of the documentation? What is missing? What is insufficiently explained? And where does it excel?

Share this article:

You can leave a response, or trackback from your own site.

2 Responses to “Android’s ContentProviderOperation: “withYieldAllowed” explained”

  1. amay82 says:

    Thank you for this article. I’m still not sure if the withYieldAllowed() should be set in the *first* operation of a batch (“Normally a sync adapter should insert a yield point at the beginning of each raw contact operation sequence in the batch.”):

    insert raw_contact withYieldAllowed(true)
    insert contact_data_row1
    insert contact_data_row2
    insert contact_data_row3

    or *after* the operations of a batch:

    insert raw_contact
    insert contact_data_row1
    insert contact_data_row2
    insert contact_data_row3 withYieldAllowed(true)

    • Sorry for this. I have to reword my post, I guess.

      You should set the withYieldAllowed() call at the beginning of each block of operations. Thus your first example would be the correct way.

      In applyBatch() both the calendar as well as the contacts provider both call mDb.yieldIfContendedSafely() before they apply the current instance of ContentProviderOperation. Using withYieldAllowed() you kind of split your transaction into multiple smaller transactions. Would you call withYieldAllowed() at the end, one operation might not make it to the database and which could lead to inconsistent data.

      Your question of course supports my point that Google has to update the documentation :-)

Leave a Reply

You can also subscribe without commenting.

Subscribe to RSS Feed My G+-Profile Follow me on Twitter!