您的位置:首页 > 移动开发 > Android开发

关于 Android 异步消息处理机制 Handler

2016-04-29 02:24 639 查看
详细的介绍可以看洋神的 Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系,我在这里只是简单的回顾一下。

一图胜千言



Looper.prepare() 创建线程相关的 Looper 和 MessageQueue,Handler 将消息放入 MessageQueue,Looper.loop() 循环读取 Message 并交由 Handler 进行处理。

Handler 的基本用法

从 Looper 的文档上可以看到最通常的用法

class LooperThread extends Thread {
public Handler mHandler;

public void run() {
Looper.prepare();

mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};

Looper.loop();
}
}


比较简单的用法:

调用 Looper.prepare() 来初始化 Looper

创建 Handler,通过 handleMessage 来处理消息

启动消息循环 Looper.loop()

然后就可以通过 mHandler 来向该线程发送消息了,也就实现了线程间的消息传递。下面来简单走读一下源码。

Looper

public final class Looper {
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;  // guarded by Looper.class

final MessageQueue mQueue;

public static void prepare() {
prepare(true);
}

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}

/**
* Return the Looper object associated with the current thread.  Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
...


Looper 主要方法就这几个,构造方法是私有的,提供了静态方法供我们创建实例。从 Looper.prepare 可以看到有初始化 Looper,并将其放入了 ThreadLocal,且保证一个线程只能持有一个 Looper。MessageQueue 是在 Looper 构造方法里创建的,所以是一对一绑定的。

prepareMainLooper 也是初始化 Looper 的,只是它比较特殊,创建的是 UI 线程的 Looper,并且不需要我们手动调用,这也就是为什么在 UI 线程不需要再初始化 Looper 了。通过 Android Studio 的 Find Usages [option + F7]功能可以轻松找到 ActivityThread.main()方法里初始化了 MainLooper。

Looper.prepareMainLooper();
...

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

Looper.loop();


Looper.loop() 的作用是是启动消息循环,分发 msg

/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}

msg.target.dispatchMessage(msg);
...
}
}


从代码上看也比较容易理解,从消息队列中获取消息,然后通过 msg.target.dispatchMessage(msg) 分发处理,留下的问题就是

msg 怎么进入的 MessageQueue

msg.target 是谁

Handler

一般情况下我们是通过
Handler handler = new Handler()
来创建 Handler,其调用了有参的构造方法

public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}

mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}


可以看到 Handler 默认关联当前线程的 Looper,当然也可以指定其他 Looper。

当通过 Handler.sendMessage 发送消息时,最后调用了 enqueueMessage

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}


可以看到 msg.target = this,也就是当前的 Handler,而 Looper.loop 中分发消息的时候 msg.target.dispatchMessage(msg) 也就将消息交回了 Handler 进行处理。

最终 Message 分发的方式

Handler.dispatchMessage

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

private static void handleCallback(Message message) {
message.callback.run();
}


带 callback 的 msg , 直接调用了 run

mCallback != null, 也就是通过非空构造方法创建的 Handler

继承 Handler 的子类实现的 handleMessage 方法

Activity.runOnUiThread

runOnUiThread(new Runnable() {
@Override
public void run() {
//
}
});


这是一种常用的给 UI 线程发消息的方式

public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}

public final boolean post(Runnable r){
return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}


代码也非常好理解,在 UI 线程的话直接调用 run 方法,非 UI 线程则 postMessage,对应 Handler.dispatchMessage 的第一种处理方法,还是直接调用 run 方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 异步 handler