This post comes out of a crash fix that I just did for my codebase.
We had been facing some ui delays in our app for past some time now and it was beyond a comfortable user experience now. So we decided it was time to sit down and solve the issues behind this.
As you’d have guessed, we were doing some things on main thread that we shouldn’t have been doing. The tool that helped us track down the exact things is BlockCanary. It’s a great tool that prints the whole stacktrace of the method call that’s holding your main thread.
So, we quickly pushed all of this work to our background thread. In doing so, we didn’t realise that we were creating a handler
in of those things for the current thread so that we could post some runnables on it.
If you have worked with handler
s before, you’d have guessed it by now. The app started crashing.
And the reason was, handler
requires a looper
to be running on a thread and we didn’t create one. It was working correctly before because the code was running on main thread and it already has a looper
.
The crash fix was pretty easy but I went ahead to learn more about the looper
s and I must say they are pretty interesting! The purpose of this post is to share that with you.
looper
transforms a normal thread which terminates when its run() method returns into something that runs continuously, which is needed in a GUI framework. It provides a queue where jobs to be done are enqueued.
An Android app can’t run on a normal thread. A thread called “main” or “UI” starts your application and draws all UI. So the first screen is displayed to users. What next? The main thread terminates? No, it shouldn’t. It should wait until users do something. But how can we achieve this behavior? Well, we can try with Object.wait() or Thread.sleep(). For example, main thread finishes its initial job to display first screen, and sleeps. It awakes, which means interrupted, when a new job to do is fetched. So far so good, but at this moment we need a queue-like data structure to hold multiple jobs. Think about a case when a user touches screen serially, and a task takes longer time to finish. So, we need to have a data structure to hold jobs to be done in first-in-first-out manner. Also, you may imagine, implementing ever-running-and-process-job-when-arrived thread using interrupt is not easy, and leads to complex and often unmaintainable code. That is what looper
is all about.
The official document of looper
class says:
Threads by default do not have a message loop associated with them and looper is a class used to run a message loop for a thread.Now I guess you understand what it means.
In our case, we wanted a message queue for our background thread as well, so we created a looper
for it.
How did we do it?
You just have to call prepare
before creating the handler, then loop
after creating the handler and when you are done, quit
. That’s it.
Cheers !
Let me know in case of any doubts.
References : https://stackoverflow.com/questions/7597742/what-is-the-purpose-of-looper-and-how-to-use-it
Comments
Post a Comment