Handler机制

前面介绍了线程的基本概念以及状态,这里来介绍Android中多线程通信Handler机制。

概述

总结一下自己从书上看的内容:
首先Handler通过send或post来将Message放入MessageQueue中,Looper通过loop来不断的轮循MessageQeueue里面的Message交给Handler处理。
*每个Thread只对应一个Looper
*每个Looper只对应一个MessageQueue
*每个MessageQueue中有N个Message
*每个Message最多指定一个Handler来处理

刚开始学有些奇怪,为什么Handler要sendMessage,然后由Looper将MessageQueue里面的消息发送过来,又交由Handler自己处理呢?自己直接处理不好吗?

这就好比你(Handler)接收到一个任务(Message),然后任务又不紧急但又必须处理,这样你就可以由该任务订个日程(MessageQueue),然后日程闹钟响起的时候,你就知道要来处理这个任务。

来看看自己创建一个线程利用Handler机制,需要怎么做

class MyThread extends Thread { 
    public Handler handler; 
    public void run() { 
        Looper.prepare(); 
        handler = new Handler() {
            public void handleMessage(Message msg) { }
        }; 
        Looper.loop(); 
    }
 }

首先看到的是Looper.prepare(),然后Looper.loop(),来看看Looper里面源码

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

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 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;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    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.recycleUnchecked();
    }
}

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
}

可以看到prepare执行了Looper构造方法,将Looper对象保存到ThreadLocal当中。
ThreadLocal是一个特殊的全局变量,因为它的全局性只限于自己所在的县城,而外界所有的线程(即便是同一进程)一概无法访问到它,由这也可知每个线程的Looper是独立的。
Looper构造方法还创建了一个MessageQueue对象,应该早有预料,loop()方法显而易见就是不断轮循MessageQueue取出其中的Message来交给Handler(msg.target)处理

看完Looper就来看看Handler的源码

public class Handler {
public void handleMessage(Message msg) {}

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

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

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

在写应用程序时一般new出一个Handler对象都会重新写他的handlemessage方法(或者通过callback)在执行真正要做的任务,除此之外,我们还会通过Handler.sendMessage()这个方法来把发送消息,由源码跟进可知最后都会调用sendMessageAtTime方法,而这个方法就是一开始所说的msg压入MessageQueue。其中还看到msg.target=this这条语句,在Looper.loop()中看到msg.target.dispatchMessage(msg),这就是要发送消息给handler了,源码最终调用的是我们重写的handlemessage方法。这样一切都理清楚了。

MesasgeQueue里面出入队列等操作,学过数据结构理解起来也是很轻松

HandlerThread代码

public class HandlerThread extends Thread {
    
    @Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }
    
    // If the thread has been started, wait until the looper has been created.
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}     
}

由HandlerThread源码可知这是一个封装了Handler机制的线程,并且不用手动的调用Looper等方法,其中使用wait/notifyAll解决了多线程中子线程1获取子线程2的Looper对象为空的问题。这样便成功避免了一些异常等问题。

我们应该如何应用

mThread = new HandlerThread("handler_thread"); 
mThread.start();
mWorkHandler = new Handler(mThread.getLooper());

这样就可以在子线程应用Handler了

你可能感兴趣的:(Handler机制)