Android queries modifying a variable in the UI Thread - android

I have a simple query returning a Cursor, and then I walk the cursor and create objects that I throw in an ArrayList, like this:
List<Element> myElements = new ArrayList<Element>();
Cursor c = db.query(...);
c.moveToFirst();
while (c != null && !c.isAfterLast()) {
myElements.add(new Element(cursor.getString(0).........)); <-- CREATING THE ELEMENT
c.moveToNext();
}
...
You get the idea.
The problem is that I need to run 4 queries like this hitting different tables, etc, but they all return the same Element object in the end (after walking the cursor).
Being a good Android citizen I created a class extending AsyncTask to avoid hogging the UI Thread. Also, I want to run the 4 queries in 4 threads to speed things up.
The question:
in my onPostExecute(Cursor c), I'm running the logic marked as "CREATING THE ELEMENT" above. If I run 4 threads with 4 queries and all modifying the List, will I have thread conflicts touching the same variable from them? How do I prevent that? Do I gain anything by threading this if the list I need to modify is synchronized? I mean, the threads will have to wait in line anyway, I might as well write the 4 queries and run them sequentially... or not?
I understand I want to keep this out of the UI Thread. The question is if I want to create 4 threads (each running in an AsyncTask) or just ONE AsyncTask that runs the 4 queries sequentially.
Thanks!
Llappall

will I have thread conflicts touching the same variable from them?
You will certainly have race conditions - if you are fine with it then no issues.
How do I prevent that? Do I gain anything by threading this if the list I need to modify is synchronized?
I don't think so.
I mean, the threads will have to wait in line anyway, I might as well write the 4 queries and run them sequentially... or not?
The question is if I want to create 4 threads (each running in an AsyncTask) or just ONE AsyncTask that runs the 4 queries sequentially.
I would run all the 4 queries in one AsyncTask, creating 4 AsyncTasks would be a lot to do and maintain.

Vector, as opposed to ArrayList, is synchronized and thread safe, so I would suggest to use it instead.
http://download.oracle.com/javase/6/docs/api/java/util/Vector.html
Another alternative would be to create a new List per thread and then use Collections.addAll() to incorporate the elements to the original list.
To answer the question whether you would gain anything by starting multiple threads, probably the answer will depend on how expensive are the queries you are doing. Starting a new thread has an intrinsic overhead, so you want to make sure that the query you are starting is worth the cost.

Related

calling stage.act call in different thread a good idea in libgdx?

Will calling stage.act on a seperate thread within an infinite loop is a good idea?
Is there any pros and cons on this approach?
I've tried doing it,but im not sure if this will cause problem in the long run. it looks faster though.
From LibGDX documentation:
No class in libgdx is thread-safe unless explicitly marked as thread-safe in the class documentation.
You should never perform multi-threaded operations on anything that is
graphics or audio related, e.g. use scene2D components from multiple
threads.
From Stage api:
The Stage and its constituents (like Actors and Listeners) are not thread-safe and should only be updated and queried from a single thread (presumably the main render thread).
So how you can see, it's a bad idea.
We always write stage.act in render method and purpose of that we get time(dt) between 2 render method(Gdx.graphics.getDeltaTime()) call. You can write stage.act in your own loop. but for that you have to manage stop calling stage.act().
If you want to set same anim speed in every device then you should use
stage.act(Gdx.graphics.getDeltaTime()).

How to transfer RealmResults accross threads

I'm using a recycler view in my app and would like to do some computation on a background thread, obtain a list of RealmObjects, and refresh my adapter to it.
As a bit of background, I have a non trivial sorting requirement, and the recycler view needs to display objects that result from queries on different tables(though they still produce the same object type). I don't want to do these potentially expensive queries on the main thread.
What is the best way to do this? AFAIK, I can
Get a list of ids(String) from the background thread, and do a query on the main thread. So I would do something like realm.where(ObjectA.class).in(listOfIds).findAll(). However, I don't think I have a guarantee that the order of the collection is the order of my listOfIds, which i have sorted in the background. I could then sort the realm collection manually.
Or, I can do a realm.copyFromRealm(listOfObjectA), assuming I have gotten a list of objects from my background thread. With this way it feels cleaner to me but i obviously lose the auto-refreshing functionality, not to mention that it will be memory-intensive. It seems that the expensive copying would take place on the main thread, which would undermine my efforts to move things into the background thread.
I was hoping there was a method that would allow me to transfer RealmResults or RealmList from one thread to the other. Does anyone have recommendations on how to do this?
findAllSortedAsync
I have a non trivial sorting requirement
If this sorting is based purely on your RealmObject fields, you can use RealmQuery.findAllSortedAsync(...) method, which will execute the query and sorting for you on a separate worker thread. This is the best option. If it's possible, you can also do sorting in two stages, one using findAllSortedAsync and second one on main thread on already obtained objects - possibly the second stage would not be as costly if the results are pre-sorted by realm.
and the recycler view needs to display objects that result from queries on different tables
You can look for a possibility to create a linking between these objects, for example if RealmObject A has a field b, you can sort A by fields of b also - this could fix your problem, and keep everything in one realm query.
Requery with sorted IDs (NO)
Get a list of ids(String) from the background thread, and do a query on the main thread...
You're right - there is no guarantee of the results being returned in the original ID list order, so this is not really an option.
copyFromRealm
Or, I can do a realm.copyFromRealm(listOfObjectA)...
That is correct, however you have to be aware of the limitiations and memory overhead using this method, namely:
you get a snapshot of the data and have to manually update the recycler with new snapshots
single change to an object conforming to your original query will trigger an update and, possibly, sorting all over again
It seems that the expensive copying would take place on the main thread, which would undermine my efforts to move things into the background thread.
Not really, if you perform copyFromRealm on thread A and pass the list to thread B, the hard copying of the values from realm will be executed by thread A, so it's fine.
You can not move "live" RealmObjects across threads, so the two options you've laid out are pretty much what you're left with.
If you do your query on the background thread and use copyFromRealm to create disconnected objects, sort them, and then pass those back to the main thread, that will all happen on the background thread, so you're fine there.
(Small note: if you display the data in a different format than it is in Realm, you could also map it to a class that's quicker to then populate your views from instead of using the Realm object in the UI, since you lost the sync features anyway.)
Otherwise, if you need them to be connected to Realm, I think you will have to do the ID list transfer and suffer the cost of sorting them on the main thread.
Use copyFromRealm method
In java:
MyRealmObject unManagedRealmObject= realmInstance.copyFromRealm(myRealmObject);
Well in kotlin, we can do it in a more better way:
var nonRealmObject: MyRealmObject?=null
set(value) { // here value is child of RealmObject
if (value!=null)
field = realmInstance.copyFromRealm(value) // converting RealmObject to unmanaged realm object
else
field=null
}
Now when you assign:
nonRealmObject = someRealmObject // set(value) method will be called and it will convert realm to unmanaged realm object
Note: realmInstance is an instance of Realm already created, if you create new reference make sure to close it when your work is done.

Android : Updating a list while in use

I am writing an OpenGL game and have a list of objects to render in the rendering loop, at the same time, updates from the server update this list of objects to render in a asynchronous task.
If I pause the rendering of the objects while the array gets updated obviously you see that on screen.
Would making a copy of the list, updating that and then copying it back (pause the render) be the best way?
Try the CopyOnWriteArrayList, which is a thread-safe version of ArrayList, which makes it possible to add elements to the list while traversing it.
A CopyOnWriteArrayList will allow multiple threads to access the list at once, as #Egor suggested, but I'm not sure it'll be fast enough.
Both reader and writer will interfere with each other all the time, and your users might notice it.
Give it a try. If it works - great, if not, you should have three copies of the list - one the reader (your rendering loop) accesses, one waiting for the next iteration of the rendering loop and another updated by the writer (the server update thread).
Use the three lists like so:
List<info> _readerList, _waitingList, _writerList;
In your rendering loop:
while(true) {
if(_waitingList!=_readerList)
_readerList = _waitingList
render list
}
In your service update thread:
while(true) {
read data from server
update _writerList
if there were updates {
_waitingList = _writerList
}
}
Before you start rendering, initialize _waitingList and _writerList to be two different lists with the same content, and start the loops.
This way you have no locking at all, and your two threads don't interfere with each other. The only point of contact between the two threads is the _waitingList reference, and both threads change that in one atomic operation.
The down side for this is that you'll have to wait until both the render loop and the server thread complete an iteration before the user sees the result.
CLARIFICATION:
It just occured to me that I missed an important point -the writer should create a new list and not reuse the same instance, otherwise after a couple of iterations both reader and writer will use the same list, and you're back to the same old race condition.

ListView.setListAdapter is very slow

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.

android cursor movetofirst performance issue

i am trying to optimize my application. I noticed that cursor.movetofirst() method somehow slowing the performance of my code.
Cursor cursor = myDbHelper.getDayInfo(new SimpleDateFormat("yyyy-MM-dd").format(myCalendar.getTime());
above line executes in 10 ms in 2.1 emulator, and
if(cursor != null && cursor.moveToFirst())
this line took about 1.6 seconds. I made little search about this. Somepeople say make it in another thread or in asynctask, but this will make the code more complicated.
I 'm just trying to figure out what is actually happening to this cursor.
Can anyone simplify or give a hint about database performance increase related to my question?
It's been a while since this was marked answered but you never really got a great answer here. Even on a very large table a single row query should usually take much less than 1.6 seconds. The reason it's slow is that you don't have an index for the column(s) that you are querying on so it has to scan the entire table to find those values. If you create an index you can cut the time down to a fraction of a second.
It is natural, that moveToFirst() method gets much more time that other code. The data enquariyng actually takes place, which invokes database communication, data reading and so on. You actually can't do anything with it. The advice was right - move all the long operations to AsyncTask.
If the dataset held by the cursor is large, moving the cursor around takes time. You have to perform such data-intensive operations on a separate thread. Using an AsyncTask might make your code a tiny bit complex but it's worth it. This against the user thread being blocked at the cost of a broken UI experience.

Categories

Resources