In my own testing I did not encounter this issue but once my app was published the ANRs started flooding in. My app currently has 22 ANRs with some being reported as many 100 times. All of the traces seem to be from attempting to create a new Realm instance on the UI thread.
"main" prio=5 tid=1 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x4183ede0 self=0x417548b8
| sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684
| state=S schedstat=( 2816413167 710323137 3658 ) utm=215 stm=66 core=1
at io.realm.Realm.createAndValidate(Realm.java:~495)
- waiting to lock <0x41df9c98> held by tid=12 (IntentService[UASyncService])
at io.realm.Realm.create(Realm.java:486)
at io.realm.Realm.getInstance(Realm.java:404)
at io.realm.Realm.getInstance(Realm.java:366)
at io.realm.Realm.getInstance(Realm.java:347)
I believe the root of this issue is, as beeender mentioned, that I have an open Realm transaction in a worker thread which is blocking my attempts to get a Realm instance on the UI thread causing ANRs.
I will update again later after I have a solution.
*Edit: Added updated information.
Realm no longer has this issue.
For reference my solution at the time was:
Thanks to beeender for pointing me in the right direction and linking this PR https://github.com/realm/realm-java/pull/1297
Issue
When there is a pending Realm transaction, any call to Realm.getInstance on a different thread will block until the pending transaction has been committed or cancelled.
In my case I have an IntentService which populates my Realm with existing user data, meanwhile I try to display any current data by querying Realm on the UI thread. Although the queries are simple and don't cause any issues normally, if there is a pending transaction in the IntentService, calling Realm.getInstance will be blocked, blocking the UI thread, potentially causing an ANR.
My first attempt at a solution was to pull beeender's PR branch and create a jar. I believe this fix did get me one step further, allowing the Realm instance to be created without blocking, but the UI thread was still blocked by small transactions I was trying to perform on UI thread.
Solution
The solution I implemented involves several steps:
Create duplicate objects for all of my models. The duplicates do not extend RealmObject (since RealmObjects cannot be used across threads.)
Move all accesses to Realm onto background threads. Basically I wrapped my queries in AsyncTasks and added listeners which return the non-RealmObject version of the model.
Make more small transactions rather than fewer large transactions. Where previously I began and committed transactions on either side of a loop which created many new RealmObjects, I now begin and commit the transaction per object. The purpose of this is to reduce the total uninterrupted time that Realm may be in an open transaction state so my queries providing data for the UI can complete without having to wait as long.
Conclusion
I was initially hesitant to use Realm due to it still being in beta as well as the caveat that RealmObjects cannot be used across threads. After some tests I felt confident that I could perform simple queries on the UI thread without issue (still with a guilty feeling in my gut though.)
Overall Realm is a great project to keep an eye on but I feel that it is not ready for large scale commercial projects. Using Realm on this project may have saved some time upfront but it cost many displeased customers and a difficult to diagnose issue.
*Edit: Clarified issue.
Realm's introduction example shows them using an AsyncTask to do their reads and writes.
Any costly I/O, be it from the network, a database, or a large file should typically be kept off the main thread as it will cause a sluggish UI. Without seeing your code, I'd guess that if you're getting an ANR you're probably doing something too complex for the main thread.
Related
I'm wondering what the possible drawbacks are to running my queries on the main thread. At the moment I am loading data from a database using Room and am using this data to generate graphs for the user.
I have already tried putting my queries into separate threads using a runnable, but I am having issues with the application attempting to use data which has not yet been loaded due to the separate thread not finishing it's operation in time. I understand that I could implement some sort of listener or notification, but even then, the user will have to wait an undetermined amount of time before they may view the content because the data for the graphs that they are wanting to view never loads before the button that loads them is clicked.
I have done quite a bit of research and found that it is unadvisable to put the queries on the main thread because it could possibly hang up the thread for a long time and give a poor user experience. So, assuming that I will never exceed 1400 data members, should I worry about this? Are there any caveats that I have not been informed of?
Edit: I am testing the device on a Samsung SM-J106B which is running Android 6.0.1 and I have not noticed any impact on performance even when loading the max of 1400 data members.
DB queries could take long enough that they would cause the UI to skip frames causing a bad visual experience or worse trigger an app not responding exception.
My app has a pretty big database, especially one of the tables - it has like 2 million entities. In the next app release we are doing a huge update - dropping one of the columns and replacing it with another one. For the biggest table this takes ~ 13 sec.
The problem is even though i have put this update in a background thread(still it is in the onUpgrade method of the SQLLiteDatabase), it still blocks the UI thread and causes an android os popup to appear - prompting to either kill the app or wait.
Is the onUpgrade method actually blocking the UI thread, or am I doing something wrong?
Use StrictMode API to detect the exact cause of the UI thread blocking.
I would recommend you to a service and initiate this db upgrade if it's going to be huge one, also provide a loading screen if you don't want see the UI immediately.
Hope this helps.
There was actually another database process that was blocking the UI thread. I managed to identify the problem using the StrictMode API. Thanks #albeee
How do I check why an application is running slow? More precisely, which lifecycle method is taking more time to execute in Android.
I have already tried logging the lifecycle methods of each activity and fragment, but I could not figure out the reason for the delay.
The onCreate is called, but then there is quite a delay (around 1s) before onResume is called.
Owing to the above delay, the user feels like the application is not very responsive.
The delay is reduced to about 100ms for high end phones. But it the old 2012-2011 models that have this huge delay.
A few ideas on how to investigate further into identifying the root cause of delays, and how could we optimise apps to navigate through screens faster.
Thanks in advance.
If you are processing heavy load of data (including complex UI rendering) in main thread , then you can find this kind of message in logcat:
W/Trace(1274): Unexpected value from nativeGetEnabledTags: 0
I/Choreographer(1274): Skipped 55 frames! The application may be doing too much work on its main thread.
This may cause your application to slow down with respect to rendering
UI
Suggestable Fix
Fixing this requires identifying nodes where there is or possibly can happen long duration of processing. The best way is to do all the processing no matter how small or big in a thread separate from main UI thread. So be it accessing data form SQLite Database or doing some hardcore maths or simply sorting an array – Do it in a different thread
Now there is a catch here, You will create a new Thread for doing these operations and when you run your application, it will crash saying “Only the original thread that created a view hierarchy can touch its views“. You need to know this fact that UI in android can be changed by the main thread or the UI thread only. Any other thread which attempts to do so, fails and crashes with this error. What you need to do is create a new Runnable inside runOnUiThread and inside this runnable you should do all the operations involving the UI. Find an example here.
So we have Thread and Runnable for processing data out of main Thread, what else? There is AsyncTask in android which enables doing long time processes on the UI thread. This is the most useful when you applications are data driven or web api driven or use complex UI’s like those build using Canvas. The power of AsyncTask is that is allows doing things in background and once you are done doing the processing, you can simply do the required actions on UI without causing any lagging effect. This is possible because the AsyncTask derives itself from Activity’s UI thread – all the operations you do on UI via AsyncTask are done is a different thread from the main UI thread, No hindrance to user interaction.
So this is what you need to know for making smooth android applications and as far I know every beginner gets this message on his console.
I have an application that is doing a LOT of sqllite transactions, I currently have a bit of a hang because I am doing the sqllite actions on the UI thread... yes bad...
so I made each item have a thread and execute on it assuming sqllite api was smart enough to FIFO them.. nope ... now I get database is locked exceptions
this says it should work
without completely rewriting my code, and having a list of transactions queue up and execute them all on the same thread (many different classes, would be kind of a pain)
is there a way for me to check, and not execute a thread unless there isnt a lock? a lock check per se, or something similar that would get this to work, is efficient and isn't a huge rewrite?
Thanks
My answer that you quoted seems to be confusing. You don't have to do anything special when you are accessing the same Android database using the same database object with multiple threads. Under the covers, Sqlite has it's own locking to guarantee that the database will not be corrupted. To quote my answer;
Sqlite under Android is single threaded. Even if multiple threads were using the same database connection, my understanding is that they would be blocked from running concurrently. There is no way to get around this limitation
It has it's own locking which serializes the requests. This means that adding multiple threads will not increase the performance of the database unfortunately.
As my other answer mentions, you cannot use multiple database objects to the same database from multiple threads since there is no locking and you will corrupt your database.
I have a certain update method in my Android App, which generates quite an amount of data - up to hundreds of database entries.
I also have a background service, aside from the UI thread. Both threads have to execute the update method, sometimes even at the same time - basically, this is about generating and caching data to display. Both the UI and background service need this data.
Currently, I have wrapped the method's execution in an ORMLite transaction, which maps to an ordinary SQLite transaction. However, I am afraid that this will bite me in the butt one day, when some race condition screws up the data cache.
The question: Do SQLite transactions protect me from concurrent execution, or should I rather implement some kind of worker thread which is spawned when the generator-method shall start, or blocking if the generator-method is already running?
UPDATE:
I have decided to not rely on SQLite logic for the protection of my high-level Java method. The solution was for me as follows:
Wrap the generating part of the method with synchronized
Introduce a variable which tracks the last time of executing the method (set at the end of the method, so it is the marker of execution END)
First thing in the synchronized section, check if the last execution is in a specific threshold (e.g. <= 100ms in the past)
If yes, skip generation
If no, perform generation
In this way, duplicate generation should not take place, since when the method is accessed from two threads at the same time, the first will generate, but the second will not. The most important part for me here is that it is still blocking, since both threads rely on the generation having taken place after they have called the method.
EDIT:
It seems I'm wrong in my below statement: The SQLite implementation is, according to many, thread safe. I have, however, bitterly experienced threading issues, especially when testing database access, but that must have been caused by other factors in my code then, I assume.
Sorry for the misleading answer.
ORIGIN:
Good question!
You should be very careful here because the standard Android database access objects (such as SQLiteDatabase, Cursor etc) are not thread-safe by default. Not even ContentProvider's seem to give you a complete protection unless you explicitly write them with multithreading in mind.
According to Android documentation on ContentProvider's and threading (almost at the end of the page):
"Because these methods [update() is one of the functions] might be called from any number of threads at the same time, they too must be implemented to be thread-safe."
I don't know if there is any explicit locking mechanism to SQLiteDatabases (as in locking the actual database file). I would assume that a transaction itself would lock, at least the very handle you access your database with. I don't know what is true for the case where you have multiple handles to your database.
Maybe you could try to implement some singleton object (A ContentProvider maybe?) to access your database with, but even then you'd have to manage some sort of "request queue" I suppose.
You should also consider not to make any calls to the file system (the database is on the file system) from the UI-thread, what-so-ever. There is no guarantee that the database will answer in time and you're likely to end up with an ANR (especially as you write "...which generates quite an amount of data").