2

Firstly I have investigated other StaleDataExceptions on SO but none really answer, or lead me to a solution to my current App design problem.

I'm creating a Music Player App, which I initially designed to query the MediaStore.Audio with a CursorLoader to retrieve information from the Content Provider - this works fine, however obviously if you have a big music library there could be a more than desirable wait time getting all the information back when the app loads each time. My second approach was to start a remote Service on app first launch, which queries the MediaStore.Audio using a CursorLoader and registers for any updates. When the Cusror is returned I then run an AsyncTask to process the information into an ArrayList of Custom POJO class that implements the Parcelable Interface which then gets marshalled/demarshalled via an Intent back to a handler in the Music App. This solution works well because if the app is closed, and reopened it just queries the Service for the latest ArrayList of custom Objects, rather than having to query the MediaStore.Audio at all - the Service implements LoaderCallback<Cursor> and always updates ArrayList of custom Objects and notifies the App if open, if not it has them ready for when the app is reopened.

Right - to the problem (ok took a bit of time, but necessary background information). The issue is : If I'm in another media app and start deleting music files in quick succession the registered Listener in my service is calledback and a new cursor is delivered, however the AsyncTask I am using to iterate over the existing cursor has a Race Condition where it is closed by another Thread / CursorLoader as the Cursor is updated - exception thrown : android.database.StaleDataException: Attempted to access a cursor after it has been closed.

The current workaround I'm using is use setUpdateThrottle to 20 seconds when registering the listener, this works, however means there is a delay in getting updated information back to the Service.

Is there any viable solution or approach where I can avoid this problem?

Thanks in advance.

UPDATE

A working viable solution, was actually quite easy to achieve - it initial problem however does illustrate my lack of experience with Loaders, however I've gained some knowledge on the way to finding a solution.

Solution:

I am still using a remote Service. However instead of using a CursorLoader - which was closing the cursor whilst I was still processing it in the onLoadComplete() callback, I am using a AsyncTaskLoader. The AsyncTaskLoader coupled with a ContentObserver can still monitor for underlying data changes from a Uri but is not directly coupled with the Cursor object like a CursorLoader. I am able to monitor for data changes and let the AsyncTaskLoader know it needs to reload data (forceLoad()), however this is queued, and doesn't affect the processing of loadInBackground() method - Once this returns, it simply cancels the task and starts the new task.

Mark
  • 9,604
  • 5
  • 36
  • 64

0 Answers0