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.