I am using a database to persist the state of a search form. I am using the onPause method to persist the data and the onResume method to restore it. My opinion is that restoring and persisting state should be a blocking operation so I plan to perform the database operations on the UI thread. I know this is generally discouraged but the operations should be quick and I think if they were done asynchronously they could lead to inconsistent UI behaviour.
Any advice
Even if you want the application to not accept user input while the slow operations are being performed, you still don't want to do them in the UI thread. This is for two reasons:
Fully non-responsive UIs are a big nono. If you need to lock your user away from interacting with the program, you need to assure him that something is actually going on - anything else is likely to be interpreted as your application being buggy. Use dialogs, toasts and/or progressbars while the application is working, as appropriate.
Android will offer users the option of force-closing applications that it thinks are hanging. You don't want this to happen during what is normal behaviour for your application is taking place.
Even if you want it to be a blocking operation, you have to show the user that some thing is happening. Because when the UI thread is blocked, the screen will not respond to any touch operation of the user. Sp, you can have an indefinite progress bar in your onPause() and onResume() methods till the persistence and restoration is done. And obviously you will have to do it in a separate thread. Because if the UI thread is not responding for sometime, android can give the Application Not Working error.
Related
Consider a simple activity containing two fragments:
RecordListFragment: A RecyclerView bound to LiveData<Record> via a #Query and a button which calls a #Delete query for a Record
RecordEditFragment: Several widgets to change the record and a save button which calls a #Insert or #Update query for a Record
The documentation for RoomDatabase.Builder#allowMainThreadQueries states:
Room ensures that Database is never accessed on the main thread because it may lock the main thread and trigger an ANR. If you need to access the database from the main thread, you should always use async alternatives or manually move the call to a background thread.
Every tutorial/blog/example I found states the same, you should not block the UI thread with database work. My instinct disagrees: There's nothing more I want when inserting or deleting data from a database than having an easy way to block the user from interfering.
If all database access happens on a worker thread one possible order of events that comes to mind is:
The user deletes Record a on the RecordListFragment
The user manages to enter the RecordEditFragment for Record a
The background thread executes the deletion
The user tries to save/update the non-existent Record a
Boom
Another scenario is:
The user updates an existing Record a from the RecordEditFragment, transitioning to RecordListFragment
Before the list has a chance to update the user reenters the RecordEditFragment for Record a
The RecordEditFragment opens with old data
The background thread executes the save
Boom
These are classic race conditions when working asychronously and I cannot imagine that this is actually best practice on Android but I cannot find any documentation that states otherwise. Are these scenarios actually possible or does Android prevent stuff like this from happening? Why not just block the UI for a simple task like inserting a record to not have any possibility of a race condition?
You can block the user from interfering with tasks without "blocking the UI".
You said:
There's nothing more I want when inserting or deleting data from a database than having an easy way to block the user from interfering
You can definitely change the UI so that it won't let the user do something while you have background processes or whatever you want running. That is not what "blocking the UI" is. Blocking the UI means blocking the UI thread from being able to operate.
Modern Android development, including built in functionality with Kotlin Coroutines, in some ways prevents you from blocking the UI thread by not even compiling until you fix your code. But it's possible that you could be supporting older versions of Android or else not using those language features, so it is still up to you to not write code that will run slowly on the UI thread. This makes it so that your UI seems to be responsive even if the things going on in the other threads might be taking a while.
So, if you need to write to RoomDB or run a network request, that should go on another thread like the IO thread.
See https://developer.android.com/guide/components/processes-and-threads
for more information regarding Android processes and threads (specifically read the sectino about Threads), or for more specific information about how Kotlin Coroutines help check out https://developer.android.com/kotlin/coroutines-adv
Especially, note the following quotes from the Android developer link above:
When the thread is blocked, no events can be dispatched, including drawing events ...
... the Android UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread
So go ahead and fire off that background work on another thread, and change your UI to show that it's doing something until that other thread completes. Then you have prevented the user from interfering and you've also made the app work in a way that doesn't appear broken.
I'd like to know the code or configuration needed to set that.
In my app, there are some places where I'm willingly make the app to sleep for several seconds, as it's needed for some reasons, with a Thread.sleep(long millis) function.
Problem is that on some Android APIS, at least on 25 and 26, usually that system message pops up in few seconds, confusing the user and maybe even causing the application not to fulfill the needed operations that need to happen while that sleep is happening if the user ends the app, which might cause even malfunctioning of the application.
I'd like to find a way of either forcing Android to wait for a good time like, for example, 1 minute, or to make Android aware that it's not that app isn't responding, that is willingly on a Thread.sleep function.
Is there any way to do that?
I'd like to find a way of either forcing Android to wait for a good time like, for example, 1 minute, or to make Android aware that it's not that app isn't responding, that is willingly on a Thread.sleep function.
TL;DR there is none.
Android apps should at all times be able to yield their position in the foreground to other apps. It's up to the users if they want to wait while some lengthy download is taking place or if they prefer to do something else and come back later.
You can't execute Thread.sleep() on the UI thread for long because this would "freeze the UI".
An example: Users should be able to leave your app by pressing the BACK Button at any time they wish to. If your method is blocking the UI thread, Activity#onBackPressed() can't be executed so the users can't quit.
What can you do? Move the heavy work to another thread (using e.g. AsyncTask or IntentService or some plain worker thread) and show some type of progress indicator to the users if necessary. You can/ should also toggle visibility or enabled state of Buttons etc. if required to avoid clicks which can't be processed at that point in time.
I think you have an implementation problem. The system message, known as ANR (Application Not Responding) occurs when the application cannot respond to user inputs, this may be caused by Ui thread blocking and that may be your case.
To avoid blocking the UI Thread just run your long time operations asynchronously. There are many ways to do that. You could use AsyncTask, AsyncTaskLoader, Thread, RxJava... Here you have some links to help you with that:
https://developer.android.com/training/articles/perf-anr
https://google-developer-training.gitbooks.io/android-developer-fundamentals-course-concepts/content/en/Unit%203/71c_asynctask_and_asynctaskloader_md.html
http://www.vogella.com/tutorials/RxJava/article.html
I am unsure if there is a need to do processing in a background thread for content resolver insert functionality. I did it as a part of UI thread and the application runs file. But need to know if it is right calling inserts directly on ui thread.
I'd recommend against it. Database writes are slow, and should be performed off the UI thread where possible. It may not be a problem for you now, but you may find that as your database grows or the nature of your application changes and you start writing more data, your UI thread will start to lag behind.
You may also find that this kind of operation in its current form might not run so smoothly on lower-end devices.
In addition to these issues, if you plan to share your database between multiple threads, concurrent writes can and will be blocked by the database lock to assure data integrity; this in turn may leave your UI thread hanging.
So, although it may not be a problem right now, you can save yourself a lot of time in the future by implementing and working with a design pattern that does ensure your transactions occur off the UI thread.
Whatever you do, make sure you give yourself a pat on the back for making this consideration in the first place!
As suggested by developers, The sqlite operations must be performed on the Background thread. But in some cases, if the sqlite operations are being performed on Background thread And during that, the user remove the application from recent task.
This causes app to be gone in an undesired state. Sometimes cause a crash next time when I open my app.
If I perform sqlite operation on UI thread, everything goes fine.
My app has lot of sqlite operations to be performed at lot of times. How should I deal with this.
I have developed an application that is used very intensively for hours, makes a lot of web services calls, uses a lot of async tasks and does a lot of operations on an sqlite database. The problem is that absolutely randomly the display dims, as if it goes in power saving mode (this is happened also when the battery was charged) and the UI does not respond at all (the log written for buttons click are not written). If I click the home button the phone works correctly and every app works fine. If I go back to my app the display dims again. I really don't have any idea about the cause of this behavior, I really hope some of you can help me because my boss wants an explanation because the customer wants an answer.
EDIT: I've noticed that when the problem occurs, it's just after unlocking the screen, so it should have something to do with app resuming, but I don't really have any idea of what is causing this behavior.
It seems that some operations may be blocking the main UI thread and the app goes to not responding state. Check if any such intensive operations are done in UI thread.
As jaibatrik says, this might be caused by doing too much work in the UI thread rather than in background threads, AsyncTasks etc. One way this may be achieved which is less obvious is if all the work is correctly done in a background thread (of some type) but a UI thread operation is waiting for the outcome of a background thread operation.
you could prevent display dim like this.
ll.setKeepScreenOn(true);
you should handle onresume(), onpause() & co.
maybe you create memoryleaks within your backgroundtasks or services.