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.
Related
I saw some articles about CursorLoader like this, but I still don't understand the particular purpose of using it.
I developed apps with SQL and cursor retrieving. The point is it was very fast. I queried and parsed cursor with >500 record and 8 columns by a few millisecond. So didn't notice any delay event on old phones. So why do I need to use it?
A CursorLoader is used ostensibly to query a ContentProvider with LoaderManager.LoaderCallbacks<Cursor>.
There are two things that you need to keep in mind for understanding the CursorLoader:
It loads data on a separate thread.
It monitors the underlying data source for updates, re-querying when changes are detected.
Now coming to the LoaderManager. Simply stated, the LoaderManager is responsible for managing one or more Loaders associated with an Activity or Fragment. Each Activity and each Fragment has exactly one LoaderManager instance that is in charge of starting, stopping, retaining, restarting, and destroying its Loaders. These events are sometimes initiated directly by the client, by calling initLoader(), restartLoader(), or destroyLoader(). Just as often, however, these events are triggered by major Activity/Fragment lifecycle events. For example, when an Activity is destroyed, the Activity instructs its LoaderManager to destroy and close its Loaders (as well as any resources associated with them, such as a Cursor).
The LoaderManager does not know how data is loaded, nor does it need to. Rather, the LoaderManager instructs its Loaders when to start/stop/reset their load, retaining their state across configuration changes and providing a simple interface for delivering results back to the client.
So you see, all this is not easily possible when you use a simple AsyncTask and query an SQLite database. This is why the framework provides CursorLoader and LoaderManager:
To perform queries on a separate thread.
To monitor the data source for changes and update the UI.
To integrate easily with the life cycle of Activity and Fragment.
The practical purpose is simply how Android handles UI elements (that is on the main thread). Basically, anything that may be a long running process, run it in a background thread so you don't lockup the main thread. This can't be said enough. After Gingerbread this has been more enforced by Android itself. Check out SQL helper. To get to the point in regards to opening an SQLite connection and its "speed":
Because they can be long-running, be sure that you call getWritableDatabase() or getReadableDatabase() in a background thread, such as with AsyncTask or IntentService.
By using CursorLoader, it makes your life easier if you need ContentResolver and are using SQLite DB. More importantly, it runs on the background. Just because you've never seen the DB lock up doesn't mean it doesn't happen. Better safe than sorry, and the main thread will thank you :)
Use the CursorLoader from Support Library to run asynchronous queries in the background. In this way, you ensure that data loading does not cause “Application Not Responding” messages.
A CursorLoader runs a asynchronous query in the background against a ContentProvider and then it returns the result back to the Activity or the Fragment from where it is called.
The main advantage is that it helps the user to interact with Activity or Fragment while the query is still running in the background.
My application has :
Activity A that reads from sqlite database
Service with notification that writes to the database
on clicking Notification, Activity A opens up
the reading by ActivityA is very small task(in reference to time taken to read)
but the writing by the service to the database is very long(it sometimes takes 5-10min)
now when the service is running and i click on the notification, ActivityA that has to read from the database cannot perform its reading as there is already a service writing to that database.
so activityA has to wait (for 5-10min) to read from database.
on researching further i came across this
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#beginTransactionNonExclusive()
when i try to implement this in my method inside sqliteopenhelper class i get error as my application uses min api 10. so how do i get this method working for api 10 or is there anyother way to have parallel database access
?
is there anyother way to have parallel database access ?
I think there is no special way how to achieve it. You should use classic Java synchronization for synchronized access to your database.
Most important thing is that you have to make sure you have only one connection to database (you can't write/read from two different connections in the same time). And try to think about an usage of Singleton. In this case (and also in others) it's very efficient and clean solution and you can avoid many problems with access to db.
You mentioned that your task can last 5-10 min.
In similar cases every user should know that you are performing some calculations in the background e.q. show some progressDialog, progressBar or simply start animation of image.
If you are showing some data for example in List this is good reason to use lazy loading.
Have look also at these articles:
Android Sqlite Locking
Using Singleton design pattern for SQLiteDatabase
Loaders
monitor data source and deliver new results
After a configuration change : no need to re-query the data
I read the android guide about Loaders.
I read Alex Lockwood 4 parts tutorial . Tested his sample app too.
Tried to read the Google App for I/O 13, there's a Stream feature and reading its code find out it uses Loaders since it provides code to create a StreamLoader. Here is the Link
I suppose they use it to monitor for new data and add them to their view.
Same for Alex's app. There's an observer and when there is new data entries triggers a refresh for the UI.
So far it seems to me, Loaders are ideal choice for a "livescore" app. When there's a new update ( which means a new data entry ) it appears on your screen.
Maybe something like Twitter. New messages for you, custom Observer to notice for changes, custom Loader brings the data and an adapter to display them. No need to "pull-to-refresh".
But then again Twitter has its own RESTful API which kinda does the same job. No need for a pointer to the new data. ( don't know how they do it but I guess somehow the "push" new data to your device ).
So my question is :
Loaders are best option when we want to observe a data source and change our view so it will display the new data?
Are there any examples/app I can check dealing with that logic : monitor the data source -> get the data -> refresh UI
Any characteristic cases ( like the one with the "livescore" previously mentioned by me ) that when we have to deal with them we have to choose Loaders?
The second part of the Loaders ( configuration change, keeping the data ) I think its clear. No one want's to re-download an Image gallery when the user rotates the device.
Thank you and excuse my confusion
The best way I can describe a Loader is a Handler that is always on. Both Loaders and Handlers pass data between objects.
I agree with what you said about the "livescore" app.
The Loader monitors the source of their data and delivers new results when the content changes.
To answer your questions:
1) Loaders are best option when we want to observe a data source and change our view so it will display the new data?
A: Yes. if your data source is constantly updating. For example, like a stock-ticker app. If your data isn't constantly updating, then no, don't use a loader. For example, if your data source is only retrieved once, then there's no need for a Loader.
2) Are there any examples/app I can check dealing with that logic : monitor the data source -> get the data -> refresh UI
A: https://www.youtube.com/watch?v=3d9BeWqlfTk
Yes, they are what you want to use for the flow you're describing. Tangentially, there's also AsyncTasks and Services that have similarities.
AsyncTasks
Description (from docs):
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)
Caution: Another problem you might encounter when using a worker thread is unexpected restarts in your activity due to a runtime configuration change (such as when the user changes the screen orientation), which may destroy your worker thread. To see how you can persist your task during one of these restarts and how to properly cancel the task when the activity is destroyed, see the source code for the Shelves sample application.
If you specifically just want a wrapper to basic threading boilerplate, use an AsyncTask otherwise I'd suggest you use an AsyncTaskLoader if you need a general purpose way to run intensive operations in an Activity or Fragment. You get the same benefits from AsyncTask, but it handles lifecycle issues for you. There are also specialty loaders, such as CursorLoader that will are made to handle specific data sources and have conveniences for interacting with certain UI elements.
Services
Description (from docs):
A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
You would use a service to handle data being pushed to a phone. Otherwise, the user would have to open your app to get any pushed data. Services do not interact with your UI. So a common design pattern is to use a Service to gather data from a server (whether pushed real time or if you poll) and store it in your database for use both when your app is opened or when not. There are many other use cases for Services, but this one is probably the most popular.
Conclusion
So no, you aren't required to use a Loader to load data or do long running operations on a background thread and pass the results (or progress) to your UI thread, but they are the best option for most use cases.
In my application I need a lot of CRUD stuffs: read records from the local SQLite database, insert objects and updating stuffs. Most of the queries are so simple that they won't block even if run on the UI thread, however in this application I want to adopt the Windows Phone pattern: an out animation started immediatelty and an in animation started when the result is delivered.
I planned to use an AsyncTask for the job, however I noticed that Honeycomb (and the compat package) introduces this new Loader framework. The main advantage seems that data loaded by a Loader survive config changes. The LoaderEx project by Commonsware bridges between SQLite and the framework, but some problems arise.
Resources cleanup: I use a single activity, create the SQLiteOpenHelper in onCreate() and close it onDestroy(). Since the loader manager may still be running, i check it and set a pendingClose flag on my callbacks object, so it will close the cursor and the helper when load finishes. I think not closing the database is not harmful, but SQLite complains if you don't do it, and I don't like error messages :) The point here is that data doesn't survive config changes, so the Loader advantage vanishes
How many loaders should I create? Let's say I have the beloved Customer and Order tables. Loaders are identified by ID's like CUST_L or ORD_L, but every time the user clicks on some summary I want to bring in a screen with the detail. Should I restart a loader with different params, or should I init a new one with a random ID? This may happen dozens of times. Is the Loader framework intended for lots of small running jobs, or just for a few long running tasks?
What's the purpose of using ID's inside the LoaderCallbacks interface? Why not a simple initLoader(params, callback)? I don't think one can reuse some piece of logic inside a callback: eventually he will branch (with if-else or switch on ID) so I don't understand the point of giving an identifier to the callbacks object, instead of a naive approach one-callbacks-per-operation.
I'm asking this because the whole framework seems overengineered to me and without real utility. I don't understand the point of centralizing code with a LoaderManager, and I can't see any new opportunity AsyncTask did not offer.
The only win point is config changes survival, but I can't exploit it because of resources cleanup, and I can't figure out an alternative way to close the SQLiteOpenHelper because (quite obviously) the SQLiteCursorLoader requires it but clean it up is up to the user. So AsyncTask seems the winner choice here, but maybe I'm missing something.
Content providers are much more powerful than "raw-DB" approach. Lots of links on stackoverflow lead to discussions on this.
LoaderManager tries to distinguish loaders by their IDs (what's why signature of initLoader specifies this argument). ID for loader is needed to re-deliver cached result in case if data for loader with specific ID already exists (hence no need to asynchronously re-load it again).
restartLoader call forces LoaderManager to initiate async opertation specified by previously created loader. initLoader attempts to reuse existing loader before creating a new one.
Fragments and Activities have their own LoaderManagers that don't overlap.
My experience shows that even though using Content Providers sounds like overkill to implement, it actually pays off pretty good in the future. Performance hit is insignificant (tried measuring it), UI-Data bindings are added out of the box (because of content observer and CursorLoaders being able to subscribe to Uri notifications), synchronicity implemented by framework via loaders. IMHO, whenever database is needed, using content provider with loaders most of the times is the best solution you can come up with.
Other scenarios that involve using database directly, will force you to implement everything manually.
I'm currently building an android application with quite a few different connected activities. In each activity I've got a private updateView() method to update all the textViews and stuff on that screen. This gets called in the onResume() method so that each time the activity comes to the front it's views will be updated.
Is this the right way to do things or is there a more standard pattern for keeping your views in sync with the data?
I think that you are doing this correctly. onResume would be the perfect time to update your views, I assume you are only updating if there is actually new data to be displayed?
If retrieving the data during the updateView method takes a long time then you should do it in an AsyncTask to avoid clogging the UI Thread which will make your app hang.
In fact any data retrieval like getting data from the web or reading from your apps database should be done in an AsyncTask. This is because even if your data retrieval seems to take milliseconds on your device it may conceivably take longer on another, less powerful device.