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!
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'm new in Android and multithreading programming and I read in the Android.developers docs that:
It is not recommended to manipulate a view from an other thread than
the UIThread.
Ok I accepted the rule but now I would like understand why? Anyone have a simple example for me to understand why?
Thanks in advance for your help
As was stated in the comments, to avoid race conditions is part of it. Its also just a bit of bad practice. UI Thread should handle UI issues, that's what its there for. Other threads should handle other issues, that's what they're there for.
Consider the situation of having a class that modifies a TextView based on some remote query. For this you should use something like AsyncTask which allows callbacks to the UI Thread.
Now if there is ever and instance where multiple threads are working on the same UI component, what may happen is that the "wrong" (unintended) one finishes first. This is a race condition.
Also, good programming encourages a separation of concerns. You don't have the manager working on the painting that the artist is working on, so why would we imitate this behavior in software?
The upshot is: the UI should always be responsive. So if you have
some operation that will take enough time that the user will notice,
you might want to consider not running it in the UI thread. Some
common examples are network IO and database accesses. It's something
of a case-by-case basis though, so you have to make the call for
yourself a bit
A thread should be used in a long running process that would block
the UI from updating. If it's more than a second or two you
might want to put it into a background thread and notify the user
with a dialog or spinner or something. If you lock the UI thread for
more than 5 seconds the user will be prompted with a kill or wait
option by the OS.
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.
In my app, I have a ViewPager with +/- 10 pages. When the app is first opened, all the pages are instantiated and immediately begin to load data to display. Each page (which are fragments) creates an AsyncTask to query a database and populate itself with the appropriate data. Here's the problem: even though the work is being done on separate threads, the UI stops updating during the database queries (which are done sequentially, and take 1-3 seconds total). This happens both on my Nexus 5 and a crappy old Samsung phone, so I know the problem is not that the hardware just can't keep up.
So ultimately, I'm wondering why the UI thread is blocked by work done on a background thread. My understanding of threading was that doing work on one would not block the other for an extended period of time. If my understanding is wrong, please explain how. Thanks in advance.
I don't think code is required here, but if it is, let me know and I will post the relevant portions.
It stops animating immediately after the first database query begins and starts animating again immediately after the last database query completes
It is possible, then, you are not doing the work on a background thread that you think you are. You may be doing the work on the main application thread.
Traceview can help you identify what you are doing on the various threads, and StrictMode can help you with obvious problems (disk I/O and network I/O on the main application thread).
In this case, you may be getting caught by how you are doing your work:
Each page (which are fragments) creates an AsyncTask to query a database and populate itself with the appropriate data.
If you are doing your query in doInBackground() but are not touching the resulting Cursor also in doInBackground(), the query actually wasn't done yet. The Cursor is a SQLiteCursor, and it lazy-executes the query when the data is first used. This is another one of those "really cool ideas that just plain suck in how we do things nowadays". A workaround is to call getCount() on the Cursor while you are in doInBackground(), to ensure that the query actually is executed on the background thread.
My Android application includes an SQLite database with an SQLiteOpenHelper class to help manage it. During application use, the user may perform some operations such as adding/deleting/updating etc on the database.
At some points the size of the operation will be known, like this:
user clicks button to save item
the SQLiteDatabase performs a single insert query
user continues using app
At other areas of the app, the operation may be large, like inserting 10+ items into the database all at once.
Questions:
should I thread simple operations like inserting/updating/deleting/viewing 1 item?
will it take longer to insert 1 item into a table which contains many items(like 30+) than it would take to insert into a table with no items?
if i don't need to thread such simple operations, at what point do you suggest i start threading them?
when i say thread i mean using a thread that is not the main UI thread.
edit: I realize that small operations do not take much time and i could very well get away with doing them on the main thread. I am just concerned that it would be bad practice to be executing them on the main thread and would like clarification!
General rule for everything: If it's fast enough, do it on the main thread. If not, use a worker thread.
Unless you have a ridiculously huge database, a single operation almost never warrants a separate thread. Databases in general are designed to scale well, but of course a very big database (10,000+ rows?) will be a bit slower than a small one. 30 rows, however, is nothing.
I would start threading stuff if you have a lot of operations going on, like a bunch of queries, or complicated queries that span several tables.
As with everything - profile your app, and if it's too slow, optimize. Don't write an awesome synchronized super-duper multi-core-ready database handler if none of your queries takes longer than 2ms.
Always measure before you optimize!
Make sure that DB operations you do affect user experience and than start looking for a solution.
If database stuff gets slow, then use AsyncTask, which was designed to perform tasks in the background, and then update the GUI on EDT.
There is absoulutely not reason to use a thread here. Just return the cursor, extract the information from the cursor and return it to the main activity.
Specifically speaking a thread is something ideally that is going to repeat until something happens or it times out. Since the database you are using i'm assuming is on the phone, it would take practically zero time to access it.
Also another thing you can do is create a Utility class to assist with your activity to database interaction. It would be what your activity calls to interact with the database. Specifically the flow of control would be like this:
Activity -> Utility -> Database
Its between the activity and the database to keep them isolated from each other and make it much easier to access whatever it needs since it doesn't have to go directly to the database itself.