I'm refactoring an app I made some time ago. Back then I was taking my first steps into Android and the easy way to go was to avoid orientation changes, for almost all my CRUD operations I used the AsyncTask
class, didn't implement a Content Provider or used Fragments.
Now I have made some changes:
- I use
Fragment
s to encapsulate functionality - All accesses to my database are done through a
Content Provider
- I use
CursorLoader
s to retrieve my data taking advantage of the content observation and automatic background loading theLoaderFramework
brings.
The only problem I have now is that I'm not quite sure how to handle the rest of the CRUD operations (Create,Update, and Delete).
I've found that I can use the AsyncQueryHandler
class, but there's not enough information online.
One thing I like the Loader Framework, is that is aware of the Activity or Fragment lifecycle, but what about the AsyncQueryHandler
?
- What happens to the operations that were started with
startDelete
,startInsert
,startUpdate
when theActivity
/Fragment
undergoes a configuration change? Or when I press the back button? Or worse yet, if the activity is destroyed? - What is the expected behavior of this kind of operations in such cases? Should they be cancelled or should they continue to do their work?
All the operations I've mentioned above are not that complex. For real complex operations I've used Service
s or IntentService
s, but since I don't consider a good idea to run SQLite operations on the main thread I want to use a better solution, but first I need to know how that solution should react to the Activity
/Fragment
lifecycle events.
Any comments or suggestions would me greatly appreciated. Thanks.
If you use AsyncQueryHandler you have to take into consideration that this abstract wrapper is created and executes provider operations on the thread that it was started on. If you call this from UI thread the callbacks will be sent to the UI thread. If you call this from another working thread, the callbacks will be sent to that working thread.
This is not bound to the lifecycle of the fragment or the activity, ContentProviders don't have an lifecycle.
The AsyncQueryHandler at an basic level, creates an Message object which is added to the MessageQueue of an single background thread. No matter from which activity/fragment you use the AsyncQueryHandler all the Message objects will end up on the same MessageQueue. Once the background thread processes an request it will send the response back to the instance of the AsyncQueryHandler from which the request was initially made.
My recommendation is to use the Loaders from Android. These are directly tied to the lifecycle of the activity/fragment. You can have multiple Loaders in a LoaderManager(one LoaderManager per activity/fragment) which allows to do more complex operations. Your activity/fragment will automatically be notified when the content has changed(very useful when you want to combine it with your custom methods for CRUD operations or if you need to use long running services). Another very important feature they have is that they will always reconnect to the last Loader, thus you will avoid re-querying your content.
I recommend you search for some tutorials for implementing Loaders in Android. You can start with these:
Answer for your last comments:
I suggest to use the EventBus library (https://github.com/greenrobot/EventBus) to make the communication between your AsyncTasks/Thread and your other components. You can start by creating an abstract AsyncTask/Thread and on top of that to make your specific command. For example:
In the abstract class you could make some DB initialization, verification or anything else that might make sense for your application.
In these specific classes, just add your logic of the CRUD operation.
To have control over these threads, like when they should be stopped, paused, resumed you could create and ThreadPool manager which controls your threads. You can read more how to achieve this here: Thread Pool