How to transfer RealmResults accross threads - android

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.

Related

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

The efficiency of Parcelable vs Reading from the database

I have a fragment that lists "Semesters" in the following way: It accesses the database, generates an array that is then translated into views via a ListAdapter.
In that fragment there is also an add button that opens a new activity, wherein the user can create a new semester that is also being inserted into the database in the same activity.
After creating a semester I obviously would like to show it when the user goes back to the list.
For that I have 2 options:
Send the created Semester back as an object to the fragment. The problem is that it requires me to implement the Parcelable interface on most of my classes as they are nested, which would be really tedious.
Make the list re-read the semesters from the database and recreate the view from scratch.
My question is; which way would be faster and more efficient?
Databases could get big overtime, but same for parcel objects, especially when they are nested and there are Lists of custom objects and such, which makes this decision much more critical.
Parcels are super fast. It's essentially binary packed data and it's really memory and CPU efficient.
That said, it really depends on the size of the database. If it's relatively small (say, under 100 rows returned in the list query), I'd just requery it in onStart or onRestart. Makes everything much easier and more consistent. If that query takes noticeable time when returning to the list, I'd send it in the Intent.
Don't optimize (by e.g. making everything Parcelable) without being sure the database access is the bottleneck.

Android: multiple threads writing on SQLite database

In the onCreate() method of my main activity I call the constructor of my dbManager, I call the open function that creates an instance of a SQLiteOpenHelper and than I call the getWritableDatabase() on it.
Within the UIThread I add records to the database and save those records to an ArrayList. Two other threads check the ArrayList do stuff and than update the list and the database.
Now I want to add a button in the UI to delete both database and list records using an AsyncTask.
I've read that the SqliteOpenHelper object holds on one database connection. So if there is one helper instance there is only one db connection. This connection could be used from multiple threads and the SqliteDatabase object uses java locks to keep access serialize. So If I have multiple threads writing on the database, a thread will wait until the previous one has finished his operation?
Adding the new functionality (remove all) could create problems, because I have to avoid that one of the two threads may try to edit a record that no longer exists. How can I achieve my goal? Thanks.
The databese:
As long as you use only one helper, you are thread safe without a need to do anything.
In a multi threaded app, you'll need synchronized only on the creation of the helper.
You can use transacion if you want to define a critical section (more than one atomic operation).
Wrap each call with getWritableDatabase() and close(false):
public void doSomething() {
SQLiteDatabase tdb = getWritableDatabase();
dbInstance.writeSomething(tdb, 1);
close(false);
}
In this way I have multiple threads reading and writing to the database without any problem.
You app logic:
Use memory to keep track of object state, and use the database as storage only. So if one thread deletes rows from the database - you can immediately update your objects in memory, and handle your ui accordingly.
If your data is very large, than you can keep in memory only a SparseArray of dirty rows id.
It may be useful to synchronize some operations here.
So If I have multiple threads writing on the database, a thread will
wait until the previous one has finished his operation?
Doesn't need to be so. See this for more details. Anyway, this is up to the DB engine and should be transparent.
Adding the new functionality (remove all) could create problems,
because I have to avoid that one of the two threads may try to edit a
record that no longer exists. How can I achieve my goal?
Have only one thread update the DB. Other threads only modify the ArrayList -also watch out because ArrayList is not thread-safe, consider using Collections#synchronizedList().

How to load data to make them visible in an ActivityList?

I'm relatively new to Android and have the following question. I have a local DB on the device from which I want to display the content in an ActivityList. Let's say there is a table "person" on the DB containing general information like "name, surname etc."
Every row in the table should be displayed as an item within the ActivityList.
I know that there exists a sort of Adapter with which I can directly fill the ActivityList with my table data, but is this the way to do it?
Isn't it better to load all the data at startup and then hold them for the entire session and pass the data from one activity to another(or make them static..) if necessary, instead of loading the data every time I change to another Activity?
If I would have a normal Java application I would load the Data at startup and then just work with the loaded objects (at least for reasonable data sets).
Doesn't it make sense for an Android App too?
I will up-rate every answer that makes sense to me.
Thanks!
Slash
I would have a look at the ContentProvider.
You can use it to query your database and then show the content in the ListView using a CursorAdapter.
You need to use an Adapter if you want to work with ListView. So, that is a must. And you can set the Adapter data from your Activity.
As for the "sense" question, it probably makes sense. But as always it depends on a few things:
Will this data be used through out the application? Then it absolutely makes sense to load it once and use it everywhere. How you do that is up to your needs, static access or passing the data, all should work.
And DB access is always expensive. And if you have lots of rows, the loading process from the database can be extremely slow. So, again, load it once and use it everywhere is a good plan.
But be careful about blocking the UI thread when you load this data. You should never access DB from your UI thread. Instead use a worker thread or AsyncTask.

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