Skip to main content

Android Loopers

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 handlers 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 loopers 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

Popular posts from this blog

Android : AbsSavedState cannot be cast to $SavedState

Android AbsSavedState cannot be cast to $SavedState I came across a strange crash today. This is the stacktrace : Fatal Exception: java.lang.ClassCastException: android.view.AbsSavedState$1 cannot be cast to android.widget.ScrollView$SavedState at android.widget.ScrollView.onRestoreInstanceState(ScrollView.java:1810) at android.view.View.dispatchRestoreInstanceState(View.java:14768) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3123) at android.view.View.restoreHierarchyState(View.java:14746) at android.support.v4.app.Fragment.restoreViewState(SourceFile:470) at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1326) at android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(SourceFile:2323) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(SourceFile:2136) at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(SourceFile:2092) at androi...

Android Tip : Handling back button in Fragments

Android Tip : Handling hardware back button in Fragment and DialogFragment This post explains how to handle hardware back button in a Fragment OR DialogFragment . In DialogFragment, it’s quiet straight forward to achieve this. You’ve to get the dialog instance and set onKeyListener on it : if (getDialog() != null ) { getDialog().setOnKeyListener( new DialogInterface.OnKeyListener() { @Override public boolean onKey (DialogInterface dialog, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) { Timber.i( "hardware back button pressed" ); } } }); } This can be done in the onViewCreated callback. For fragments, this method doesn’t work and fragments doesn’t have a direct callback to catch this event. So in this case, the approach that we follow is : You...

Android Material Showcase View - Part 1

In this series, I'll be talking about a library which is used by a lot of android developers for showcasing their in-app content,  MaterialShowcaseView . I used this library sometime back for my work and had to modify it to fit my needs. In this process, I ended up digging it a lot and would like to share what I learned. The original library offers a fix set of features, which are demonstrated by the screenshots in the README. Let's jump on the technicalities right away. The original library offers two things : 1) highlighting a view ( see the README to know what I mean by highlighting here) 2) showing a content box that tells user what the highlighted view is about. Here's how it does this : The library adds a direct view child ( this class ) in the window decor view, so that it's drawn on top of your activity's view ( here ). Then, for drawing the overlay and highlighting our view, it overrides the `onDraw()` method of this view and uses android...