美文网首页
Handler机制

Handler机制

作者: Spirituality韬 | 来源:发表于2018-04-27 18:12 被阅读0次

前面介绍了线程的基本概念以及状态,这里来介绍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<Looper> sThreadLocal = new ThreadLocal<Looper>();

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机制之引路篇

    要想深入理解Handler机制,就要理解: Android为何要引入Handler机制? Handler机制究竟是...

  • Handler机制小结

    Handler笔记 什么是handler机制?handler机制的主要成员1、handler:负责发送处理消息2、...

  • Android:Handler 机制和原理?

    一、Handler机制概述 Handler机制也可以说是消息机制,Handler的运行时需要MessageQueu...

  • Android消息机制

    Handler Android消息机制主要指的是Handler运行机制,Handler底层需要MessageQue...

  • Android 的消息机制

    Android 消息机制主要是指 Handler 的运行机制。 **Handler **Handler 的运行需要...

  • Android Handler机制详解

    Android Handler机制1--ThreadLocalAndroid Handler机制2--Looper...

  • 消息机制

    消息机制Handler的工作原理 Android中的消息机制主要就是指Handler的运行机制,而Handler的...

  • Handler机制整理

    Handler机制整理目录介绍1.关于handler消息机制图2.关于handler基本介绍3.使用handler...

  • android handler 机制 很简单

    1.android handler机制 handler机制,也就是android的异步消息处理机制。但是这个机制不...

  • Android的消息机制

    Handler Android消息机制主要是Handler的运行机制,Handler的运行需要底层的Message...

网友评论

      本文标题:Handler机制

      本文链接:https://www.haomeiwen.com/subject/ewfblftx.html