Due to the amount of data, accessing (DBUtils) and processing* my SQLite DB is causing an ANR warning on some devices.
While there is some code optimization to be done, I would like such operations to be performed in a background thread, as recommended in this article: http://developer.android.com/training/articles/perf-anr.html
What would be the best approach?
- Move everything into a Service Module?
- Use the Threading Lib?
- Rewrite DBUtils to asynchronously access the DB?
- Other?
Rewriting DBUtils doesn't seem plausible to me because I also want the data processing to be done in the background.
*Initializing a fairly amount of variables and arrays based on the data loaded from the DB.
I would suggest using a Service or maybe the new CallSubExtended lib from the Probundle as from @Informatix
You can probably use the new starter service to do the things in.
Services don't necessarily run in another thread. My tests show that the Starter Service definitely doesn't. To prove this to your satisfaction, run the following code in Activities, Services, Threads, etc...:
B4X:
Sub LogThreadName(messageObj As Object)
Dim message As String = messageObj
Dim r As Reflector
r.Target = r.RunStaticMethod("java.lang.Thread", "currentThread", Null, Null)
Log("Mess: " & message)
Log("Calling Thread Name: " & r.RunMethod("getName"))
End Sub
I predict that Erel's advice will be to do everything asynchronously that can be done so (the SQL library has asynchronous methods) and only as a last resort should you consider using the Threading library.
If you have a lot of Insert and Delete statements on your database, the databasefile may be larger then needed. That's the point where you can use VACUUM to free database space. See https://sqlite.org/lang_vacuum.html for more information.
If you have a lot of Insert and Delete statements on your database, the databasefile may be larger then needed. That's the point where you can use VACUUM to free database space. See https://sqlite.org/lang_vacuum.html for more information.
I predict that Erel's advice will be to do everything asynchronously that can be done so (the SQL library has asynchronous methods) and only as a last resort should you consider using the Threading library.
The Threading library will not solve any problem here (assuming that the bottle neck is the SQL engine). You can use the asynchronous methods which use a pool of threads internally.
However the first thing to do is to optimize the queries.
1. Are you using indices to access the data?
2. How many records are you loading at once? Are they all needed?
The Threading library will not solve any problem here (assuming that the bottle neck is the SQL engine). You can use the asynchronous methods which use a pool of threads internally.
However the first thing to do is to optimize the queries.
1. Are you using indices to access the data?
2. How many records are you loading at once? Are they all needed?
The total number of tables being accessed is no more than 10 and the tables themselves are fairly small, the largest one has no more than 30 records. Worst case scenario, I'm importing 300 records. I will time the DB access and the data processing to find where the bottleneck is. I'm almost sure it's on the data processing. My code structure goes like this:
B4X:
'Pseudo-code
Open SQLite DB
Load MasterTable 'SQLQuery via DBUtils ExecMemoryTable
For i = To (numberOfRecords - 1)
Process MasterTable.Record(i)
Case "Background"
Load BackgroudsTable 'SQLQuery via DBUtils ExecMemoryTable
Get Background(MasterTable(i)).Properties
Case "Foreground"
Load ForegroudsTable 'SQLQuery via DBUtils ExecMemoryTable
Get Foreground(MasterTable(i)).Properties
Case "Actor"
Load ActorsTable 'SQLQuery via DBUtils ExecMemoryTable
Get Actor(MasterTable(i)).Properties
...
Next
Setup GameAssets 'Based on the obtained data
Edit: Indeed, I might be able to transfer some of the heavy work done by B4X code into SQL queries.
I've found the bottleneck. It's not on the DB access. Turns out the problem is on my data processing code.
I will restructure it from scratch and as soon as I have it done, I will reevaluate the need of running it on a separate thread.