Database calls in services - android

I've been watching Virgil's presentation at the Google I/O on REST-heavy applications.
Google I/O 2010 - Android REST client applications
Though the notepad tutorial makes database calls directly from the UI layer, Virgil suggests making database calls in a Service.
At the moment, my Activity's onCreate method uses an extended ContentProvider to access an SQLite database to query a Cursor to attach to the Activity's ListView.
I'd like to move this code into a Service. Easy enough. My question is, what is the appropriate way to transfer the Cursor back to the UI layer? I've seen many questions posed and there always seems to be someone suggesting there is a more appropriate way to do it. What is that way?
More specifically, I so far gather that the Activity should register as some sort of listener. When the Cursor is retrieved in the Service, a notification is set to the UI layer to access it. Where does the Service shove it so the Activity can grab it?
Also, my considered architecture is to have an extended Service, which is called by Activities. Inside this Service, database transactions will be made through the use of an extended ContentProvider, any listening Activities will be notified, and threads will be launched to hit web services. So, I have 1 extended Service, 1 extended ContentProvider and several extended Threads for different web services. Does this seem acceptable?

I am simply using the managedQuery call inside my Activity to get the Cursor. It's a fairly light operation and I don't think it will hold up the UI.
I've created a Service which then calls a web service to find new data. If new data is found, it is placed in my database and sendBroadcast is called. My Activity has a registered BroadcastReceiver which hears the broadcast and calls requery() on the Cursor.

Have you consider implementing Loaders?
I have an application which uses Intent services to fetch data from a server and store
them using a ContentProvider. Then the fragment or activity which needs the data implements
LoaderCallbacks<Cursor> (onCreateLoader, onLoadFinished and onLoaderReset).
At onCreateLoader I instantiate a CursorLoader object and return it while at onLoadFinished I make sure that the data from the Cursor are displayed in my Fragment/Activity.
Check the official loaders guide.

Related

Should I use a Cursor or a CursorLoader?

I have an android app in which I have a login system and some other stuff that communicate with the server. Sometimes I just get from the web server just a confirmation and sometimes I get a lot of data. So far I was using a simple database. Today I implemented a Content Provider which is working so far. To get data from the ContentProvider I used this Cursor cursor = getContentResolver().query();, but I saw that there is also the option to use a CursorLoader. What is the difference between them ? In my case what should I use ? I also saw that I have to implement it in every class the cursorLoader, can't I make a single class for it and call it when it's needed ?
As the documentation states,
CursorLoader implements the Loader protocol in a standard way for
querying cursors, building on AsyncTaskLoader to perform the cursor
query on a background thread so that it does not block the
application's UI.
This is the biggest advantage of using Loaders, i.e. it is asynchronous. Some of the other important advantages are also mentioned here.
They provide asynchronous loading of data.
They monitor the source of their data and deliver new results when the content changes.
They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data.
If you use the default cursors by querying the content provider directly then you need to handle closing them, and as you said you have huge data, you'd have to run the query code on a different thread. For all these purposes using CursorLoaders is much simpler and efficient. For code on how to use one, check this out.
As to your second question,
I also saw that I have to implement it in every class the
cursorLoader, can't I make a single class for it and call it when it's
needed ?
You can very well make a Base class that will be implementing the loader callbacks and then you can inherit that base class from all the classes that need to use the CursorLoaders.

What's practical purpose of cursorLoader?

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.

What is the use of private Content Providers?

The Android Dev Guide says
Content providers are also useful for
reading and writing data that is
private to your application and not
shared.
Generally, Content Providers are used for providing data to different applications or sharing data among them. I was wondering if there is any use to having private providers and not wanting to share it. Are there any benefits provided that a direct access to DB or file system don't provide?
Thanks,
Rajath
It automatically schedules all your server-side and synchronization DB access in a background thread. However, in your application frontend, the Content Resolver/Provider will normally execute queries/transactions from the UI thread by default. You must perform all transactions asynchronously (i.e. using a CursorLoader) to ensure that your application runs smoothly on the UI side
It localizes re-entrant DB access from the any threads that access through ContentProvider, so that all locking can happen entirely in your ContentProvider override calls, rather than keeping track of it in a DB layer, a service, and a UI layer.
As part of the above, it also provides a nice singleton interface to your data -- If you have ten Activity classes in your app, you just go through ContentResolver static calls from each one, versus needing to deal with opening/closing a SQLiteDatabase in each activity as you jump from one activity to another in your app.
ContentProvider is tied very tightly to the SyncAdapter model -- Meaning it's pretty much the only way to go if you want to keep your database in sync with a server-hosted database out on the net. (your app mirrors a REST api type of situation)
It ties into ContentResolver's ContentObserver interface -- This is an interface where (among many other useful things) a view can register as observing a specific set of data (through the Cursor to that data). Then, if you drive a change into the ContentProvider, the CP can notify the CR, which can in turn notify any relevant cursors, which in turn will requery and cause the view to update. This is much cleaner than having to manually keep track of your views so you can invalidate and redraw them.
As for re-entrant locking of the DB, it doesn't do it completely, but it helps -- your ContentProvider class implements four simple functions (CRUD interface) and, if you choose to override it, a fifth, batchAdd() -- This localizes your locking. The bone simple answer is to simply tag all four/five of those function declarations "synchronized" at the function level and you're done. Much cleaner than trying to figure out locking out from 20 places that access your DB in 5 different Activites.
For example,a multiprocess application use scenario(like: music play service usually run in a remote process), between the two process that in one application share database should use private ContentProvider.

Should content providers that check db call REST content provider if db doesn't have information

I am working on a program that has the following situation.
You want to look up a recipe, so the Activity will call the db ContentProvider.
The recipe isn't stored locally, so it will call out to a web service to get the data.
This data will be stored in the database as I am assuming that if you don't want to keep a local copy you will choose to delete it later, but you may want to shop and cook without going to the Internet constantly.
So I think my design may be getting overly complicated.
I currently have a Service that will call the REST service, and a ContentProvider to go to the database.
I am now considering replacing the Service with a ContentProvider, as I don't need a long-running Service as it should infrequently go out.
So, the Activities would call the db ContentProvider, and if the query is empty then the ContentProvider would call the REST ContentProvider, as the Activity shouldn't care where the data comes from, and the db ContentProvider would then store the information before returning back to the Activity.
Is this the best approach for my scenario, or is it bad form to have ContentProviders chained together?
I think that is quite reasonable. However, I think you could still keep the Service but just always expose the data through the ContentProvider. One glitch here is that you will have to start(or bind) the service in the ContentProvider and you will have problems when testing your Provider using ProviderTestcase2<Provider> as the MockContext does not support starting the service.
It seems a good approach. Currently I'm developing something similar and I've found this great article, where the author explains everything step by step, saying which thing for what is used for, what is the best approach and so on. Take a look at it if you are having some troubles implementing something:
http://programming-android.labs.oreilly.com/ch11.html

(best) Ways to deliver control messages to custom content provider

The android content provider has methods for the normal suspects {insert, delete, query, update} but if I want to send control messages there is no obvious mechanism.
Suppose one of the tables managed by the needs to be reset, cleared and reloaded.
How can this be done? I have several approaches each of them seems a bit hackish.
1) create an activity(or service/receiver) to to the job.
The activity does a bulk delete and insert.
This seems like the least hackish but when the content provider starts the database helper creates the tables and initializes them.
It seems inefficient to duplicate the initialization code in the content provider's database helper and in a separate activity.
2) hijack the content provider api.
A dummy table could be created where the insert (or update/query/delete) method would invoke otherwise inaccessible methods.
3) use multiple inheritance to make the content provider also an service (or activity).
This is probably closest to what I want but I don't know how to do this.
It feels dangerous, especially if it were an activity.
4) have a service content-provider pair
Similar to (3) but hopefully without the warts.
The service would have aidl for doing all the control kinds of things.
Such as, loading lookup tables, clearing tables, purging expired tuples, ...
If this were done, the service how would the service be started? by the content provider?
3) is not possible in Java.
4) would simply dump the ContentProvider and use the API supplied by the service.
There might also be:
5) Have the ContentProvider register a BroadcastReceiver via getContext().registerReceiver(), and send broadcasts to it for the different operations
I haven't tried that, but assuming the Context returned by getContext() supports it, it should work.

Categories

Resources