Android : Updating a list while in use - android

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.

Related

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.

What is the best way to use threading on a sorting algorithm, that when completed, creates a new activity and gives its data to the new activity?

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

Android Multi Threading with native code

I am working on an android project and found that an operation becomes bottleneck in performance. This operation works on a large array A and stores the result into another array B.
I found that this operation can be parallelized. The array A can be divided into N smaller segments. The operation can work on each segment independently and store the result into a corresponding segment in B.
The operation is written in native code with GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical pairs to access array A and B.
My question is that if using multi threading, GetPrimitiveArrayCritical(pEnv, A, 0) will be called multiple times from different threads. Does GetPrimitiveArrayCritical block? i.e. if one thread makes this call, can a second thread make the same call before the first one calls ReleasePrimitiveArrayCritical()?
Please help.
Yes, you can call GetPrimitiveArrayCritical() from two concurrent threads. The function will not block, and your two threads will grant access to the underlying array to native code. But on the other hand, the function will do nothing to synchronize this access, i.e. if thread 1 changes the value at index 100, and thread 2 also changes the value at index 100, you don't know which will be chosen at the end.
If you don't write to the array, you are guaranteed to be served correctly. Don't forget to ReleasePrimitiveArrayCritical with JNI_ABORT flag.
If you want to write to the array, check the output parameter isCopy as set by GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy). If the result is 0, you can safely proceed with your multithreaded approach.
If the result is not 0, ReleasePrimitiveArrayCritical() will overwrite all elements of the Java array, even if some of them was changed in Java or in C on a different thread. If your program detects this situation, it must release the array (with JNI_ABORT) and wait for the other thread to complete. On Android I have never seen an array being copied, they are always locked in-place. But nobody will guarantee that this will not happen to you, either in a current system or in a future version.
That's why you MUST check isCopy parameter.

Android accessing UI from second thread

I have hundreds of CheckBox widgets in my layout and now I'm trying to invert each of them, so if it was checked it won't be checked and vice versa. Obviously such heavy work should be done in separate thread, but the problem is that all the work actually happens the UI. Part of the thread code:
for (int x = 0; x < list.getChildCount(); ++x)
{
final WListRowTarget curRow = (WListRowTarget)list.getChildAt(x);
curRow.post(new Runnable()
{
public void run()
{
try
{
curRow.getCheckBox().setChecked(!curRow.getCheckBox().isChecked());
}
catch (Exception e) {}
}
});
}
The only thing that this thread actually can do is looping through the list and posting the Runnable for every found checkbox. The problem is that all those Runnables arrive in the UI thread almost at the same time, thus they're all executed at once... The application behaves exactly like I would run the above code in the UI thread - everything freezes. A possible solution is sleeping for some miliseconds after each checkbox so the Runnable can be executed and the UI will have time to process the events... but it's more like a hack.
How can I solve this problem?
Thanks in advance,
Snowak
I have hundreds of CheckBox widgets in my layout and now I'm trying to invert each of them, so if it was checked it won't be checked and vice versa. Obviously such heavy work should be done in separate thread
No - this is fundamentally UI work, and frankly setting a bunch of flags isn't really "heavy" work. Most of the "work" involved is actually the UI repainting - which obviously does have to be done on the UI thread anyway. Creating lots of different tasks to execute on the UI thread is just giving it more work to do - just do the whole lot in one batch on the thread without trying to use different threads.
As a separate matter, I wouldn't want to use a UI with several hundred check boxes even on a desktop, let alone on a mobile - are you sure you shouldn't redesign your UI? You may find that coming up with a more elegant design removes any performance hit anyway...
Assuming you are using a listview to display all your checkboxes you don't need to use multiple threads. Store the state of the checkboxes in a data-structure and process everything using a single thread.
While doing the processing ( sounds so wrong :-) ) just show a spinner. You can then display all the checkboxes based on the state stored in the datastructure.
Okay, I've solved the problem myself. The solution is to use Object.wait() and Object.notify() in order to wait for the Object.post() to do the job. This way I don't post more events until the previous one is executed.
The code looks like:
synchronized (someObject)
{
someObject.post(new Runnable()
{
// some work here
synchronized (someObject){ someObject.notify(); }
});
someObject.wait(); // this line unlock the object
}

Android queries modifying a variable in the UI Thread

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.

Categories

Resources