how to write a asynchronous content provider in android - android

i'm writing a content provider that provides search results for other applications.The content provider sends requests to server and parse response.now it can work successfully without asynchronous calls.but if i want a asynchronous content provider,that is,creating a thread in the query() function.and then comes the problem,how can i know when the thread is finished and has got the results.because now i just new a Thread,and start it,however,the cursor could not get results.anybody can help me?Thank you!

My application has this same problem. Depending on your situation, you may be able to return an empty cursor from your query call, and then have your views update when the cursor's data is updated. If it makes sense with your data source, you can subclass MatrixCursor (or another cursor) and make sure to call onChange when the cursor's data is updated after the asynchronous request completes - this should notify that cursor's observers of the new data, and then they can show it.

Related

database operation in android loader

I'm using a LoaderManager, the onCreateLoader method creates a new CursorLoader.
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle data) {
return new CursorLoader(context, CONTENT_URI, PROJECTION,
null, null, null);
}
Only after loading is finished in onLoadFinished() the UI is updated.
Every time I load the cusor I also need to do some database manipulation like building up a new sort index. This cannot be done asynchronously because the UI depends on this.
Is there a way to do such db operation within the loader? Or what is the best design for this problem?
As per your question you are loading your data in from database using loader and content provider
also you are working on sorting type of thing which can change the order of item in database...
So, the best way I suggest as per my experience in this type of application of do this of index sorting operation in UI only util user leave the screen...
So, In you activity of fragment override onStop method and update data indexes in database based on sorting priorities or numbers...
and after updating data to content provider just notify URI for change..
hope my point is clear to you..
Loaders were designed specifically with optimizing database access in mind. This operation does not care about updating the UI and hence has no interest in providing progress information. While it is possible (and I use this loosely), to update the UI from a loader, you should avoid this as the Loader is a wrong tool for this job. Forcing a Loader to provide progress information would break the paradigm. The Loader is expected to return only after the etire operation is complete. Instead, if you want to update the UI while doing the querying, then you should use an AsyncTask.
If you HAVE to use a Loader, then you can find a workaround here at Update progressbar from AsyncTaskLoader?. But again, since from your question, it looks like you are open to alternatives, use the AsyncTask if you need updates or you can stick to Java threads.

Disable notifications on a ContentProvider URI

I'm looking for a way to suspend notifications on a given ContentProvider's Uri. The use case is:
An Activity is bound to a CursorAdapter through a CursorLoader.
A Service may do a lot of batch, single-row updates on a ContentProvider.
The CursorLoader will reload its content on every row update, as the ContentProvider notifies listeners by ContentResolver#notifyChange.
Since I cannot edit the ContentProvider, and I have no control over the batch queries execution, is there a way to suspend notifications on a Uri (in the executing Service) until all of the ContentProvider-managed queries have been executed? I need this in order to avoid the flickering caused by the continuous requerying of the CursorLoader.
You cannot disable this mechanism in your Service. But you should try to batch them by using ContentProviderOperations.
I've written an introductory post about ContentProviderOperations and two additional posts covering the methods withYieldAllowed() and withBackReference() respectively.
Especially the latter one should be of interest for what you've described here.
With ContentProviderOperations you can batch multiple updates and inserts. If you then call applyBatch() on your ContentResolver object the ContentProvider executes them all at once.
Now I've never used Nicolas Klein's generator but since he is a very, very proficient Android developer and works at Google, I bet that the generated code makes use of transactions and calls notifyChange() only once for the complete batch at the end.
Exactly what you need.
Can you substitute your own ContentResolver?
You may try extends ContentResolver with your own class then and you will may override method notifyChange and realize your logic there.
In your Content provider class, inside query() method before returning the cursor, just comment the code which looks something like this
cursor.setNotificationUri(getContext().getContentResolver(), uri);

CursorLoader - obtain information about what has changed in db

I use standard android ContentProvider and CursorLoader from support library.
I am looking for best approach for obtain information about what has changed in database.
I know that I can read and compare cursor in function:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
}
but reading all records is probably not good solution.
Do you know good solution for this problem?
If you use a content provider, you abstract away all the changes made to the underlying database by implementing CRUD methods to insert, update, delete or retrieve an item in the database.
Sending a broadcast from the methods which you are interested would be an option to get notified of the changes being made to the database.
I recall that I had used this method to count the number of items added to the database during a refresh cycle.
Optionally you can send the Uri of the changed item as an intent extra to get a reference to the row in the database that has been changed.
Additionally you can declare a global variable to enable or disable these broadcasts to fire only during situations of interest to us.

Is a content provider a single blocking instance?

I have a content provider which can query multiple other content providers (via content resolver), and does some merging of contact data.
Basically I have extended asyncTask and handle the the data. In my main UI thread I do the following
cancelAllExistingTask();
proiverTest1 = new ProviderTask(getActivity, MyActivity.this.callBack).execute(SearchString, elementId1);
proiverTest2 = new ProviderTask(getActivity, MyActivity.this.callBack).execute(SearchString, elementId2);
proiverTest3 = new ProviderTask(getActivity, MyActivity.this.callBack).execute(SearchString, elementId3);
proiverTest4 = new ProviderTask(getActivity, MyActivity.this.callBack).execute(SearchString, elementId4);
So I create 4 instances of my ProviderTask, as part of the ProviderTask constructor, I pass in an interface which is implemented in my instance of callBack class.
class CallBackClass implements MyCallBackIF{}
The ProviderTask during doInBackground fires off a ContentResolver.query() to ONE provider. The same provider is used by all 4 Tasks. But based on the elementId it is returned to the interface via onPostExecute() w/ the elementId of the cursor array it should be placed into (see ** below).
The contentProvider parses the URI that is passed in, and based on the URI goes and queries 1 other ContentProvider for data. This could be local data, or remote from a server. Then depending on the source, it may merge it with other data (local), and provide back a new cursor w/ merged data. The individual Content Provider -> Content Resolver -> Content Provider -> Content Resolver is quite fast. And somewhat useful for providing search aggregation across a few different apps we have have. The provider does actually spawn an asyncTask to load the remote content provider data, and there is a synchronized block that waits on it to finish returning data before itself returning to the Activity. Part of the reason for this is that I could pass in a uri that has multiple providers to search & merge where it fires off more than one content resolver query into its own Merge Cursor. (But right now it is a Merge Cursor w/ 1 element that does run on an Async Task).
**
What I am doing is using a merge cursor & Cursor[] to update a list view based on the merged data from the various different providers. You may be asking, why not allow the content provider just do that work for us? We tried. It did not seem to work for us, but open to suggestions.
So as it stands if our MergeProvider Queries - ContentProvider1, ContentProvider2, ContentProvider3, ContentProvider4 and say ContentProvider3 also has to query ContentProvider 1 to merge some data. ContentProvider 3 & 4 are remote (server based)
W/ a predictive search we want search results that return back fastest to show up first. And the others to trickle in as they come back, if a new letter is typed, we want to dump the entire result set, and wait for a new query.. This is what is happening, and it seems like we are being blocked somewhere (we have tried upping thread priority of the AsyncTask, we have ExecuteExecutor w/ our own Executor & pool (upping the async task max of 10 to 100) w/ no results).
So someone types in a letter
'a' - Content Provider 1, and Content Provider 2, return in say 0.050 seconds. Content Provider 4 returns in say 0.100 seconds. And Content Provider 3 returns in 5.00 seconds. (The 5.00 delay is related to a test server we are testing on, but it has exposed the problem we are seeing w/ blocking).
now if they continue to type, and the string shows
'albert'
It may have fired off a new AsyncTask for 'al' which some return quickly, and others do not.. Say the Provider 3 is still waiting on a response.. Our code discards results if the predictive search has changed by the time the results come back. (which is fine).
so then it fires off another round of AsyncTasks 'albert'. Now remember Provider 3 is still off in it's 5 second response.
We added some logging in both the AsyncTask and in the Calling method (handler).
What we are seeing is the AsyncTask getting created, but we are not seeing doInBackground() get started until SearchProvider3 returns results (and they are discarded). I am quite confused as to why this is happening. But it is basically blocking other AsyncTask objects. Not sure what would cause doInBackground() to not be called until another AsyncTask came back unless it was because of the max limit of 10 AsyncTasks? W/ our own implementation of ThreadPoolExecutor (and even creating two different instances of ThreadPoolExecutor), we still see the same issue.
It is VERY visible if in the query method of our Provider 3, we add a thread.sleep(60000). Basically it looks like maybe 5 Async tasks get called before they start blocking. Our goal was to get local matching results back faster independent of other long running tasks. This would be more apparent on a slow (3g) network.
Maybe we should not be using Async tasks for this, and just using runnables?
Thanks.
Rather than having our app implement the ContentResolvers and all the queries, we implemented it as part of a content provider, and dispatched the searches via IntentService.
We grab a single cursor to a temp table, then w/ the Service Intent, it fires off all the other content resolver queries, and populates the underlying temp table. If it takes a bit of time on one of the intent services, the user does not really notice as the others populate it quite quickly..
Seems to have resolved our issue.

Downloading data in separate thread before initializing a ListView

I'm having issues with multithreading in my application. I know there are many posts on Threads/AsyncTasks/etc, but none seem to address my specific problem.
Basically, I get a query string in my search Activity, then send it to my results Activity, where the string is used as a SQL query, the results are returned as an array of JSON objects, then I display these objects in a ListView (which is part of the results Activity). All of my SQL connection and retrieval is done in a separate class that I call at the start of the results Activity.
MySQLRetrieve data = new MySQLRetrieve();
ArrayList<Tile> tiles = data.getResults(nameValuePairs, isLocationSearch);
The above code is how I get the SQL response and convert into an ArrayList, which I then use the populate my ListView with. getResults() takes care of all of this.
I already have separate threads working to download images into the ListView, but what I can't get to work is getting the SQL query and result to run in it's own Thread. What I want to achieve is this:
User enters search query in search Activity.
Intent is sent to results Activity, and it starts immediately.
ProgressDialog (just the animated spinner thing, not a loading bar) displays while the SQL query is taking place.
ListView populates with objects from the JSON array, lazy loading images as they come.
I have steps 1,2, and 4 working well, but 3 is the problem. I've looked up AsyncTasks, which seem to be the answer, but I just can't get them to work. Does anyone have a solution to this problem? I need to do this, so when starting the results Activity, the UI changes immediately to the results Activity and doesn't have to wait until the SQL response is returned.
And yes, I've already read the painless-threading post.
Thank you.
I would recommend against creating that ArrayList<Tile> to reduce memory consumption (and code size) and instead directly bind the SQLite Cursor to the ListView using a CursorAdapter.
That alone might just increase the performance enough that you don't need to do any async loading.
If you still want async loading, check out the LoaderManager framework (available since Android 3.0/ API level 11, with Android support package down to 1.6/4) which will automagically do asynchronous loading of your Cursor -- either using the built-in CursorLoader (if you happen to have a ContentProvider), or the SimpleCursorLoader created by a fellow SO user (if you don't).

Categories

Resources