Working with Android Things means connecting to peripheral sensors & actuators to send or receive commands and data. As with all Android development, you should be evaluating the performance impact of this and consider offloading the effort onto another thread wherever possible. So what is best practice for threading on Android Things?
Like with all demo code, the threading solutions you see in some examples have to be taken with a pinch of salt. If threading is not the focus of the example then it’s often done in the quickest or simplest way to keep the demo clear. While this might help people understand a specific point, it doesn’t help advocate the best approach to threading. Beware of blindly following the threading solutions in Android Things demo code. Let's explore some different patterns to find out why.
If you prefer a code-driven blog with less theory and more code then take a look at this blog post on best practices when threading with Android Things.
Forget threading, let’s use the one thread we have. Doing work on the Main Thread is usually a no-no in Android mobile apps, but for Android Things it is possible. Working directly on the main thread means writing the code to be executed alongside the Android lifecycle and always working in a serial fashion.
The 5 second timeout ANR (Activity Not Responding) check has been removed from Android Things. This means you can get away with doing long running operations on the main thread.
There are no other apps so the system is yours. There’s no need to worry about being a good citizen as every device is not a village. the system (and probably the entire hardware device) is under solely your control and you can make the most of all the resources available.
No need to worry about callback hell. Doing things synchronously means no thread-hopping and potentially no need to use callbacks. Everything can just be a return value and each line of code can wait for the last to finish, in theory.
If you use Android Thing’s optional UI components, it can still cause jank. This is because, like Android, UI is drawn on the Main Thread . So if you add a UI component to your app, and you’re doing work on the Main Thread, you could come back to this problem of having a janky, slow, unresponsive UI because your Main Thread is busy doing other things.
You may want to do more in the future. Right now it might make sense to do the work on the main thread because it’s ”just this one thing” and you could say YAGNI. But if you know in the future this will get more complicated (and most of the time it does), then using the Main Thread now may cause you a lot of pain refactoring away from that decision in the future.
As an Android developer, it goes against everything you've learnt so far. You will already know practices for threading and doing things as separate tasks. Why not use that knowledge if it wouldn’t cause you to slow down? Just because something is easy, eg coding without Threads, it doesn’t mean it's right. If you have a de facto pattern you use for threading, use it on Android Things as well.
The Android Main Thread is a Looper Thread, this means we can post messages to it. Posting messages in this way is asynchronous. Therefore we can post a message to do some work and it will join the back of the queue of other messages. The Main Thread executes the messages one at a time in a serial fashion.
This allows UI components to draw smoothly. Joining the queue for execution means you don’t block the Main Thread and, as mentioned earlier, this means the UI component can be drawn with less potential for jank.
You don't have to worry about how many threads there are. Sometimes hopping between threads can cause real evasive bugs, especially when debugging a lot of callbacks. This also means the problem of only being allowed to draw UI components on the Main Thread never appears.
It’s easier to understand order of execution. Always working on one thread means things cannot happen in parallel, so you are never left wondering if something could have quickly happened before you expected it to.
As with #1, you may want to do more in the future. Right now it might make sense to post the work on the main thread because it’s ”just this one thing” and you could say YAGNI. But if you know in the future this will get more complicated (and most of the time it does), then doing it asynchronously to the Main Thread now may cause you some pain refactoring away from that decision in the future.
If the messages you post are too big you can be caught out with UI jank doing long running work. You will also have less control of execution times. With both you and the system posting messages to the same queue, while you can safely assume they will be executed as soon as possible, you won’t have control over the priority or timing.
As an Android/Java developer, it goes against threading you've learnt so far. You will already know practices for threading. Why not use that knowledge if it wouldn’t cause you to slow down? Just because something is easier, eg posting single threaded messages, doesn’t mean it's right. If you have a de facto pattern you use for threading, use it on Android Things as well.
This is the neatest option - create your own threads to do long running or complex operations. This means allowing your work to be completed on a background thread using an AsyncTask, ThreadPoolExecutor, or a Loader. In all cases, a callback mechanism would inform the Main Thread of the result.
This follows conventions trialled and tested in the Android development community over time. The community has built up a set of practices and techniques that it is beneficial to take advantage of.
It separates processing and UI work. A good separation of concerns is always important, and keeping the communication and data sharing tasks separate from the UI drawing work is a part of this. It’s also the basis of many better architectures, such as Model-View-Presenter.
It’s future-proofing. No matter how complex the future communication becomes, you are now working on a background thread and don’t have to worry about overlapping other tasks or UI jank by the amount of communication happening on your thread.
It can be overly complex for simple tasks. There is no need to add extra threads (and callbacks) if the requirements stay simple.
It can be callback hell. Understanding the call flow of an application can be difficult and callbacks tend to make code less readable.
Threading should always be avoided if possible. Deadlock, Livelock and starvation are problems no developer ever wants to face. Any threading starts discussions about performance overhead and the costs of thread hopping. If possible, it’s always best to avoid this complexity.
Given the above, it can seem like there’s no right answer. Depending on your situation, you should take into account what’s going to change, when change is likely and what your development needs are, to help you make an informed choice.
Developers who are familiar with Android should find using background threads straightforward, especially when de-facto libraries are in use. However, it is necessary to make a conscious effort to write the code this way from the start.
It is important to understand that example code on the internet has often been created to explain another concept, so it uses a quick and dirty approach to threading and shouldn’t be considered best practice. Don’t let the sheer number of these examples influence what you perceive as platform best practice when it comes to threading.
and some on the Render Thread but let’s ignore that complication for now. ↩︎
We plan, design, and develop the world’s most desirable software products. Our team’s expertise helps brands like Sony, Motorola, Tesco, Channel4, BBC, and News Corp build fully customized Android devices or simply make their mobile experiences the best on the market. Since 2008, our full in-house teams work from London, Liverpool, Berlin, Barcelona, and NYC.
Let’s get in contact