Skill Level Intermediate
- [Instructor] Last week I described how you can use the Room Persistence Library to create code that manages your SQLite databases. In that exercise, I ran my code on the main thread but that's not a recommended approach. For best performance and to ensure that you don't freeze the UI thread, you should always execute your queries on a background thread. I'll show you one approach for that. First, I'll go to my database class, NotesDatabase in this version of the app and I'll comment out allowMainThreadQueries.
Then I'll run the application. When I click Run Code, the application crashes. I'll go to Logcat and show the reason. I get this message, cannot access database on the main thread. Now, this is a rule that's implemented by Room and as I showed there's an easy way around it but if you want to run your code in the background thread, you have a number of options. In the course on concurrent programming in Android I show a variety of strategies but I'm going to show one more, using the Java Executor class.
The executor is designed to manage a thread pool, one or more threads that can run concurrently but with the database operations, you can only run one thread at a time. You don't want to access the database from two simultaneous threads. And here's how you can control this very easily. In my MainActivity class, I'll declare an instance of the Java executor class. It's from Java.util.concurrent. I'll name it executor and I'll initialize it right away by using the executors class and its method SingleThreadExecutor.
Now, that means I'm creating a pool with exactly one thread. Now I'll come down here to my runCode method and this is where I'm trying to execute a bunch of database functionality, so reading, inserting, counting and querying data. I'll use the executor object that I already created and I'll call executor.execute and I'll pass in a new runnable object. Now I'll take all this code and I'll move it to the run method and that's essentially all you need to do if you don't need to communicate with the UI thread.
For the moment, I'm going to replace all the calls to the log method with calls to log.i, so I'm using Logcat for logging, not the UI thread. I'll copy that bit of code, and I'll paste it here and here. Then I'll open my Logcat window and I'll filter on MainActivtiy and I'll clear the output and I'll run the application again. When I click Run Code, I see all my Logcat output here.
Now, I'm allowed to do that because Logcat does not involve the app's UI thread. But let's say that I wanted instead to call my log method so I was logging my messages to the screen. Well, I can do that if I use an event architecture. I could either use Local Broadcast Manager which is included with the SDK or as I prefer, I can use EventBus and this application is already rigged up to use EventBus. In my modules Gradle script I have the EventBus declaration down at the bottom.
In the MainActivity I have code in the onCreate and onDestroy methods to register and unregister and I've already created a MessageEvent class that can be used to transport data around the app. So, I'll come back here to MainActivity again, and I'll go down here to log code and I'll go to the first place where I'm logging information and I'll replace log.i with EventBus.getDeafult.post and then I'll pass in a new MessageEvent and that will wrap around the message that I want to send.
I no longer need this first argument and now I'm sending a message using EventBus. Down towards the bottom of the MainActivtiy, I already have a subscribe method called onMessageEvent which receives that event object and logs its information. Now I'll select this bit of code, and copy it to the clipboard and then for the other two uses of log.i, I'll delete the beginning of the method call and the first parameter and paste in the rest.
And I'll need one more closing parent at the end. And I'll make the same change here. And there's all of my finished code. I'll once again run the application and now when I run the code, I'm logging to the screen and again, the reason I have to go through all these steps is because it's very strongly recommended that database operations be only executed in background threads. If I want to communicate from that background thread to the foreground thread, I'll need to use some sort of event architecture whether it's EventBus or something else.
The important thing to get from this exercise though is the use of the executor object. By using the executor object you're guaranteeing that you only have a single thread and you're executing all your database queries through that thread. If you try to call the execute method more than once, it will queue up the operations and execute them one at a time.
Q: Why can't I earn a Certificate of Completion for this course?
A: We publish a new tutorial or tutorials for this course on a regular basis. We are unable to offer a Certificate of Completion because it is an ever-evolving course that is not designed to be completed. Check back often for new movies.