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().
Related
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.
i want to add data in 3 tables in one database from 3 AsyncTask object. because the AsyncTask objects may run or finish at the same time and i'm adding data in my database in onPostExecute() , i want to know is it possible to do such a thing or not ?
thanx
Android SQLiteOpenHelper is synchronized by default. all you need to do is make your DB helper singleton and you will not face any problem.
Read this for more info on singleton db helper.
I have a doubt... I want to execute this code, but I don't know if it's better to do it in an Asynctask or it isn't necessary and I can execute it in the main function.. What do you think?
The SQLite Database is local, so the acces is so fast.. Thank you!
/*Here I create an object of SQLiteHelper Class*/
SQLiteHelper bbDD;
bbDD = new SQLiteHelper(getActivity());
/* Calling this method I open the database connection */
bbDD.open();
/* This method returns me an ArrayList, doing a SELECT in the SQLite Local Database*/
arrayList = bbDD.selectAll();
/* Here I Close the database connection */
bbDD.close();
Today's devices are fast enough to handle SQLite query inside main UI thread, but when you try to query big size of data inside SQLite (for example if you have more than hundred rows of data inside that database (Especially if row contains base64 encoded image strings)) user can see some UI lag, that's why query in Asynctask makes UI faster - without lags. If you don't have big data inside SQLite, there is no need to use AsyncTask for query.
No dude there is no need to write SQLite local querys in an Asyntask.
The answer to your question depend on the size of your database.
I have experienced to select hundreds of rows, with lot of columns on SQLite. It does not make the apps very lag, but it does make the apps a little bit lag (and my client can feel this). So, i moved the select operation to the onBackground in the Async class, and the apps run flawlessly again.
If you only have a little data, theres no need to put it on the background.
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.
I have an activity for initialising a game, that does multiple selects and inserts from a number of SQLite tables.
I'm trying to understand AsyncTask, but, from all the examples I've read so far, I'm wondering if I am going to have to subclass AsyncTask for every single different data operation I need to do?
For example, my NewGame Activity does the following:
1) Insert new player record into PLAYER table
2) Insert new player's pet record into PET table
3) Select cursor of n records from INVENTORY
4) Insert array of ranomly chosen inventory items into PLAYER_OWNED table
5) ....more things of a similar nature
There are going to be a few more selects and inserts for various things too, so having an individual subclass for each one is going to get crazy. Not to mention that there will be about 8 activities for this game, all relying heavily on database reads and writes.
So, basically, how do I best use AsyncTask to carry out a number of different SQLite operations?
You can pass parameters to a AsyncTask, even more, if you use nested clases, you can use global variables from inside the AsyncTask class, by using one of the above or both mentioned aids you should be able to use the same class and have it do diferent things depending on the parameter you pass. I see no real need to define multiple AsyncTasks.
You will need to define a AsyncTask in every activity.
I wrote need, because you really dont have to, but its comfortable to do it this way, and its easy to read/write code, as the AsyncTask is asociated to the activity only. This is of course suposing you use nested clases, I see no point in writing a separate class file just for an AsyncTask.