The Handler class lets you manage a thread's message queue. Each thread has a Looper object that receives and dispatches messages. For example, if the user clicks a button, that creates a message that the Looper receives and then dispatches to the appropriate part of the app framework that handles such things. A Handler lets you add messages to the queue, either right away or at particular times.
- [Instructor] Java code runs sequentially by default. That means that a code block runs from start to end within a single thread until the sequence of actions is complete. The UI thread, also referred to sometimes as the main thread, can only do one thing at a time, and if you try to do more than one thing, you'll block the UI, causing it to become nonresponsive. I'll demonstrate this by going to this bit of code, a method named runCode. Right now it's just displaying a bit of text, and I'll show the result in my emulator.
When I click the Run Code button, I get some text down at the bottom and the scroll view that's wrapping the text view scrolls down to the bottom. Now, after I've called the log method, I'll add this text. Thread.sleep, and I'll pass in a value of 3,000. That means pause the code for three seconds. The sleep method can throw an exception so I'll use an intention action and wrap that with a try catch block. Now this code looks like I should see the new text and then there should be a three second pause, but Thread.sleep runs on the main thread, and that means that I'll block the thread from executing and I won't see anything until the pause is complete.
I'll click Run Code and then wait a few seconds, and then the text appears. But this is even worse. Notice that I can click and drag to scroll the text up and down. As long as that pause is happening, I won't be able to do that. I'll click and then try to scroll and nothing happens until the pause is complete. So this is a blocking call. I'm running it on the main thread and the UI becomes unresponsive as a result. You can solve this using something called the handler class.
Each thread in Android has a queue of messages. Messages are handled by default on a first in, first out basis with something called a looper. Each time through the message loop, the looper looks for the next available message and executes it, but with handler you can delay an action. You can place a message at the end of the current thread's message queue, and you can also delay it by a specific amount of time, or execute the message at a particular time. To use the handler, start with an instance of the Runnable interface.
This is a functional interface that has just one method named Run. I'll create an anonymous implementation of the interface, and I'll make sure to include my semicolon at the end there and for this next experiment, I'll move my call to Thread.sleep inside the Run method. Then, to execute the Runnable interface, I'll create an instance of the Handler class. There are a number of different versions of the constructor, but I'll use the no arguments version.
Then I'll call handler.post and I'll pass in the runnable object. And then, once again, I'll take this log call and I'll move it up to the top of the screen. Now this looks like it might solve the problem, but it won't. I'll show the result and then explain why it's not going to work afterward. Once again, I'll click Run Code and then try to scroll, and once again, the UI is unresponsive, and after three seconds it comes back again.
Here's the problem. This call to Thread.sleep is still running in the main thread. I haven't done anything to delay that code. So instead, here's what I'll do. I'll get rid of the call to Thread.sleep and instead I'll use a method of the handler object called postDelayed. This method takes two arguments, the runnable object and the amount of time I want to delay it. Now I'm releasing the main thread for this amount of time.
The main thread can continue to do whatever it's going to do and after three seconds, this runnable object's run method will be executed. I'll use the Log.i template, and that expands, and I'll complete this with run runnable complete. I'll also add some code here to use my progress bar. Before I start the handler, I'll call displayProgressBar and pass in true, and in the run method I'll call displayProgressBar and pass in False and then I'll run the app again.
Now when I click the Run Code button, I see the message instantly and I can scroll up and down and I see the progress bar. And I'll demonstrate that again, and show that the UI remains responsive even while that pause is happening. So this is the correct technique if you want to delay execution of a task for a certain amount of time. Now, I'm not multithreading, that is, I'm not creating a background thread. Everything is still being executed on the main thread. I'm simply delaying a task for a certain amount of time.
I put the code that will execute the task inside the run method of the runnable object and then I pass the runnable object to the handler with the postDelayed method. This is a simple trick that lets you add a delay, but doesn't require the use of an actual background thread. One more note about handlers in general. If you go to the method scrollTextToEnd, you'll see that it's calling the method post from the ScrollView component. Now, ScrollView is a component, that is, it's a visible object of the screen, but it implements the post and postDelayed methods in the same way that handler does.
It accepts a runnable object that has a run method. The reason I do it this way is that I want to delay the scrolling to the end until all the other work in the UI has happened. In this case, I want the text view to display all of the new text before I scroll down to the bottom. The effect is that the UI waits until the text view has been complete updated and only then does the scroll action take place. The handler class with runnable objects and view classes that also implement the post and postDelayed methods give you better control over what happens in your Android app's UI.
First, discover how to create and start simple background threads, and how to use handlers to manage a thread's message queue. Then, learn various methods for optimizing the scheduling and performance of background tasks in Android with AsyncTask, intent services, and the JobScheduler API. Plus, explore tools that help you implement multithreading for different tasks in Android: Loader, for asynchronous data loading, and the open-source API Retrofit, for making HTTP requests.
Note: To get the most out of this course, you should be comfortable programming with Java, and should understand the most basic skills that are needed to build Android apps with the Android SDK and Android Studio.
- Creating and running a background thread
- Sending messages to the UI from threads
- Managing multiple background threads
- Managing threads with AsyncTask
- Managing long-running tasks with services
- Scheduling background tasks with JobScheduler
- Using other APIs for concurrent programming