3

I'm new to Android development. There seem to be 2 important classes when dealing with threading in Android: Looper and Handler. There are static Looper.myLooper() and Looper.getMainLooper() methods to get the current thread's looper and the UI thread's looper, respectively. However, there are no such static methods for Handler. If you want to post to the UI thread, for example, code samples suggest doing this:

new Handler(Looper.getMainLooper()).post(new Runnable() { ...

Why doesn't Handler expose a cached, static getMainHandler() method that looks like this? Wouldn't that avoid creating unnecessary garbage?

private static final Handler mainHandler = new Handler(Looper.getMainLooper());

public static Handler getMainHandler() { return mainHandler; }
James Ko
  • 32,215
  • 30
  • 128
  • 239
  • 2
    because the main purpose of `Hnadler` is to `handleMessage` which you can do only by extending the `Handler` class (or by implementing own `Handler.Callback`) – pskink Aug 16 '17 at 18:09
  • 1
    "There seem to be 2 important classes when dealing with threading in Android: Looper and Handler" -- usually, you use higher-order threading approaches (`AsyncTask`, `IntentService`, RxJava/RxAndroid, `LiveData`, etc.). `Handler`/`Looper` are low-level facilities, the sort that newcomers to Android should rarely need. – CommonsWare Aug 16 '17 at 18:11
  • @pskink Oh. Well I just want to post messages, I'm not looking to handle them. Is it OK if I cache the main handler myself in a static field? – James Ko Aug 16 '17 at 18:22
  • 1
    so you can use `View#post` (of course if you have a `View`) - if you dont have a `View`, then yes, you can simply use any singleton keeping your `Handler` – pskink Aug 16 '17 at 18:24

2 Answers2

4

Each Looper might have many Handlers. So which Handler would you return for the main Looper?

You can add a Handler to a Looper using the code you provided.

The responsibility of a Looper is to pull messages from an associated message queue, find the message's target handler, and dispatch the message to it. The handler will receive the message and execute its handleMessage(Message) callback where custom message-handling logic is specified.

To post a message to the message queue, you call Handler.sendMessage() or, similarly, Handler.post(Runnable), which uses messages internally. sendMessage() is defined on Handler instead of, say, Looper, because in this way the Message's target can be set to the specified Handler. Therefore, when the Looper receives the message, it knows what specific handleMessage of what specific Handler to run.

Finally, let's say you have a static method that returns the "main" Handler, for example, the Handler used by the system to handle things like configuration changes. That would be quite dangerous as you could call handleMessage() yourself and trigger logic that should be triggered only by the system.

Gil Vegliach
  • 3,542
  • 2
  • 25
  • 37
  • 1
    `"Finally, let's say you have a static method that returns the "main" Handler, "` - theoretically the `Looper` could have the default `Handler` that could be used to `post` custom `Runnable`s - but apparently google guys prefer sending `Message`s hence custom `Handler` with overriden `handleMessage` method is a way to follow... – pskink Aug 17 '17 at 05:19
1

The quick answer is no, I'm afraid.

The common way to do what you ask in Android is to use Activity#runOnUiThread(Runnable).

Also, as an alternative way to be able to do this from any class, I like to provide the helper you can see in this other answer.

Finally, there are other alternatives, like using RxJava (with Android bindings) or other libraries like Anko for Kotlin.

Xavier Rubio Jansana
  • 6,388
  • 1
  • 27
  • 50