关于Handler的理解

个人对于Handler的理解,用于记录和帮助理解。

Android的消息队列机制中具有三个重要元素,Handler、Looper、MessageQueue。

  1. Looper中循环取消息并发送消息
  2. MessageQueue则用来存储消息
  3. Handler则用来创建消息

Handler

Handler在android用于通信,个人接触到的普遍作用是用于更新UI。因为多线程可能会导出界面更新出错。,所以Android不允许在子线程中进行UI的更新,并给与Hnadler的通信方式。
基本用法很简单

//接收消息
Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        text.setText("hello world");
    }
};
//发送消息
//发送延时消息
mHandler.sendEmptyMessageDelayed(0,0);
//发送消息的三种方式
mHandler.sendEmptyMessage(0);
mHandler.sendMessage(mHandler.obtainMessage());
mHandler.post(new Runnable() {
    @Override
    public void run() {

    }
});

对于以上三种方式,实现方式一致,只是外在接口形式不同。源码如下:

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

最后都会执行这个方法,所以结合实际情况调用即可。
enqueueMessage方法则消息依次加入MessageQuene中。
post有所不同,内部会加载方法getPostMessage(r)

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

getPostMessage方法内部将r赋值给msg的callback

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

在Handler的构造函数中,初始化变量Looper、MessageQueue。此步骤关联Looper、MessageQueue。

public Handler(Callback callback, boolean async) {
    ...
    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;
}

Lopper

在myLooper中,拿到Looper

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

Looper不能通过new创建,只能通过peprepare方式创建。

private static void prepare(boolean quitAllowed) {
    //通过此判断保证一个线程中只有一个Looper
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

Looper构造函数

private Looper(boolean quitAllowed) {
    //因为Looper一个线程只能具有一个,所以一个线程中也只会有一个MessageQueue,并将Looper与当前线程绑定
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

Looper的loop方法用来循环消息队列,取出消息并进行发送

public static void loop() {
    //拿到Looper
    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
        ...
        //发送消息
        msg.target.dispatchMessage(msg);
        ...
    }
}

通过死循环不停的拿到消息并发送消息。

Message

随后我们进入Message方法中,查找target,发现方法

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;
    return m;
}

在Handler最终发送消息的方法中,发现同样代码

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

在我们可以通过obtain获取一个复用Message,在此方法中,将target指向了Handler,所以最终会调用Handler的dispatchMessage方法,接着查看Handler的dispatchMessage方法

//我们经常重写的方法
public void handleMessage(Message msg) {
}

/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
    //检查callback,即post发送消息时赋值的callback
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        //执行过滤器方法,在构造函数中进行初始化
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //在此调用重写的方法
        handleMessage(msg);
    }
}

//post发送请求方式
private static void handleCallback(Message message) {
    message.callback.run();
}

以上,消息发送完全完毕。

为什么Activity中不需要我们进行Looper的创建呢?
因为ActivityThread的main方法中帮助我们进行了Looper的创建。因为Looper的创建过程中绑定了当前线程(主线程),所以Handler可以在UI线程中更新UI数据。

你可能感兴趣的:(关于Handler的理解)