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.
Related
My queries with .equalTo() return out-of-date data when used with addListenerForSingleValueEvent, while removing .equalTo() causes the listener to return updated data. Any idea why?
.
I'm using the following query to fetch user's posts from Realtime Database with persistance enabled on Android:
mDatabase.child("posts").orderByChild("uid").equalTo(id)
where id is the id of the current user and each post stores its author's id as a field.
When .equalTo(id) is present, the new posts for the particular user are not returned in that query for the first few minutes. Even more, it seems to affect other queries for the same root ("posts") that contain .orderByChild. Eg, following would also fail to recognise the new post:
mDatabase.child("posts").orderByChild("archived")
Once I remove the .equalTo(id) the behaviour goes back to normal. I'm using addListenerForSingleValueEvent. Tried it also withaddValueEventListener which fires two events, one without the new post, one with it. Without .equalTo(id) both single and non-single listeners return the new post in the first callback. Restarting the app doesn't seem to help straight away - the first event stays out-of-date for the next few minutes. The new post is successfully fetched by different queries in other parts of the application (eg mDatabase.child("posts").child(id))
Any idea why .equalTo() causes such behaviour and how to avoid it (other than using non-single listener and ignoring first event)?
Note 1: same thing happens for .startAt(id).endAt(id)
Note 2: other parts of the Realtime Database are functioning normally, device is connected to the internet and new posts are containing the valid uid field matching the current user.
Update 26/10/2016
Calling mDatabase.child("posts").startAt(key).limitToFirst(4) also produces similar behaviour when trying to query a segment of the database (in our case to implement infinite scroll). It seems that explicitly adding .orderByKey() fixes that particular problem: mDatabase.child("posts").orderByKey().startAt(key).limitToFirst(4).
Though the issue outlined in the original question remains.
I've ran into the exact same problem as you, and after experimenting with almost everything, I've managed to solve it on my end.
I'm scanning barcodes and fetching foods that have the scanned barcode:
Query query = refFoods.orderByChild("barcode").equalTo(barcode);
query.addListenerForSingleValueEvent(new Value ... })};
On my rules i had
".indexOn": "['barcode']"
and after i changed it and took the "[]" out as in:
".indexOn": "barcode"
it started working delay free, where before it would take something like 5 minutes to udpate.
I will start this by saying that on iOS this algorithm takes, on average, <2 seconds to complete and given a simpler, more specific input that is the same between how I test it on iOS vs. Android it takes 0.09 seconds and 2.5 seconds respectively, and the Android version simply quits on me, no idea if that would be significantly longer. (The test data gives the sorting algorithm a relatively simple task)
More specifically, I have a HashMap (Using an NSMutableDictionary on iOS) that maps a unique key(Its a string of only integers called its course. For example: "12345") used to get specific sections under a course title. The hash map knows what course a specific section falls under because each section has a value "Course". Once they are retrieved these section objects are compared, to see if they can fit into a schedule together based on user input and their "timeBegin", "timeEnd", and "days" values.
For Example: If I asked for schedules with only the Course ABC1234(There are 50 different time slots or "sections" under that course title) and DEF5678(50 sections) it will iterate through the Hashmap to find every section that falls under those two courses. Then it will sort them into schedules of two classes each(one ABC1234 and one DEF5678) If no two courses have a conflict then a total of 2500(50*50) schedules are possible.
These "schedules" (Stored in ArrayLists since the number of user inputs varies from 1-8 and possible number of results varies from 1-100,000. The group of all schedules is a double ArrayList that looks like this ArrayList>. On iOS I use NSMutableArray) are then fed into the intent that is the next Activity. This Activity (Fragment techincally?) will be a pager that allows the user to scroll through the different combinations.
I copied the method of search and sort exactly as it is in iOS(This may not be the right thing to do since the languages and data structures may be fundamentally different) and it works correctly with small output but when it gets too large it can't handle it.
So is multithreading the answer? Should I use something other than a HashMap? Something other than ArrayLists? I only assume multithreading because the errors indicate that too much is being done on the main thread. I've also read that there is a limit to the size of data passed using Intents but I have no idea.
If I was unclear on anything feel free to ask for clarification. Also, I've been doing Android for ~2 weeks so I may completely off track but hopefully not, this is a fully functional and complete app in the iTunes Store already so I don't think I'm that far off. Thanks!
1) I think you should go with AsynTask of Android .The way it handle the View into `UI
threadandBackground threadfor operations (Like Sorting` ) is sufficient enough to help
you to get the Data Processed into Background thread And on Processing you can get the
Content on UI Thread.
Follow This ShorHand Example for This:
Example to Use Asyntask
2) Example(How to Proceed):
a) define your view into onPreExecute()
b) Do your Background Operation into doInBackground()
c) Get the Result into onPostExceute() and call the content for New Activty
Hope this could help...
I think it's better for you to use TreeMap instead of HashMap, which sorts data automatically everytime you mutate it. Therefore you won't have to sort your data before start another activity, you just pass it and that's all.
Also for using it you have to implement Comparable interface in your class which represents value of Map.
You can also read about TreeMap class there:
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
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).
I have a ListView which potentially contains thousands of rows, generated by a CursorAdapter. Only eight or so rows are visible at any one time. I've had reports that starting up this view can take many seconds, and can cause an ANR (force close).
I'm doing the DB query in a background thread. I've verified that newView and bindView in my adapter are only being called for the number of visible rows.
Once the list is displayed, actually scrolling up and down the list is very fast.
The delay is in the call to ListView.setListAdapter, which has to run on the UI thread. Why does this seem to depend on the total number of rows in the result set, rather than the (much smaller) number of rows which are actually being displayed? Is there any way I can optimize it?
This question was asked a couple of years ago in this thread. I'm hoping to get some fresh insight and more concrete examples of potential workarounds.
UPDATE
I have tried to work around this by using CommonsWare's EndlessAdapter. I limit the initial query to (say) 20 rows using a LIMIT clause in my DB query, and I increase this limit and resubmit the query every time I hit the bottom of the list.
(As an aside, I haven't found a way of appending just the new results to an existing Cursor, so I'm increasing the LIMIT value each time and then re-fetching the whole lot up to the new limit in a new Cursor.)
Strangely, this workaround doesn't seem to improve the time it takes to perform the initial setListAdapter call. When I run it on a data set containing only 20 rows, the call to setListAdapter is really quick. When I run it on a data set containing hundreds of rows, but limited to return just 20, it takes over a second.
UPDATE 2
By forcing the query to execute in the background thread with a simple getCount(), as suggested by CommonsWare, I've cured the initial blocking of the UI thread on starting the activity. The UI is still blocked, though, when returning to this activity from a child activity. The ListActivity by default seems to want to re-run the query on the UI thread.
I have worked around this by removing the adapter in onStop(), and recreating it in onStart(). Thus the query is always performed in the background regardless of the direction we're moving through the activity stack.
I'm doing the DB query in a background thread
If all you do in the background is call query() or rawQuery(), the query is not actually executed. It will be lazy-executed when you first try using the Cursor (e.g., getCount()). So, the right recipe for doing a query in the background is a rawQuery() followed by something like getCount() in the background thread, to ensure the query really is executed.
When I run it on a data set containing hundreds of rows, but limited to return just 20, it takes over a second.
Off the cuff, that would suggest that the speed issue is not the time required to read in the results, but rather in computing the results in the first place.
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.