Handler详解

一.什么是Handler
Handler是Android机制的一个上层接口,Handler通过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue。
1.可以让对应的Message和Runnable在未来的某个时间点进行相应处理
2.让想要处理的耗时操作放在子线程。让更新UI的操作放在主线程

二.Handler使用方法
1.post(runnable)和sendMessage(message)
这俩个方法都是返回了sendMessageDelayed();
区别是post返回的sendMessage里的参数,是通过getPostMessage方法把Runnable对象设置给了Message的callback字段,最后将Message对象插入消息队列

private static Message getPostMessage(Runnable r) {
    //获取一个message,把Runnable封装成了一个Message对象
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

而sendMessage方法因为他的参数是message对象,不需要转换直接就能存到消息队列中.

三.Handler机制
Looper:是每一个线程中所独有的,用来为一个线程开启一个消息循环,它通过它的loop()方法读取它下面MessageQueue的消息,读取到消息后把消息发送给Handler来进行处理。

MessageQueue:是一个消息队列,它是一个先进先出的方式来管理的
在创建Looper的时候,其实它已经创建了MessageQueue,所以创建Looper的时候,Looper和MessageQueue已经关联到了一起。

Message:是消息对象,它里面有很多参数(what,arg1,arg2,obj(可以传一些复杂的对象))

Handler:它有两个作用,发送消息和处理消息,处理Looper发送过来的消息,Looper发送消息也是通过Handler来进行的,Handler发送消息不是漫无目的发送,它不能发送到其他线程,它只能发送到它相关线程的MessageQueue当中,而MessageQueue又是和Looper关联的,所以说Handler要发送消息必须有一个维护它的Looper,这时候就把Looper,MessageQueue,Handler关联到了一起

我们在创建Handler时,他的构造方法已经通过Looper.myLooper()创建好了Looper实例,并通过创建好的Looper对象的mQueue创建一个MessageQueue实例

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());
            }
        }
        //创造了Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //通过Looper创造了MessageQueue
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    } 

这样Handler和MessageQueue关联到一起,而MessageQueue又是Looper管理的.

myLooper方法是通过ThreadLocal.get()获取,
ThreadLocal 线程本地存储区(Thread Local Storage) 通过不同的线程访问同一个ThreadLocal,不管是它的set()方法还是get()方法,它们对ThreadLocal所做的读写操作仅限于各自线程的内部。也就是不同线程彼此不能访问对方的ThreadLocal。
这就是Handler里为什么要通过ThreadLocal来保存Looper,这样它就可以使每一个线程有单独唯一的Looper。

Looper.prepare()方法中的“ sThreadLocal.set(new Looper(quitAllowed))”,就是它创建了一个Looper对象,并且把这个Looper对象设置给了ThreadLocal,保证了每一个线程Looper的唯一性。Looper内部维护一个MessageQueue。
这时候整个的MessageQueue通过Looper跟线程关联上了,这样不同的线程就不能访问其他的消息队列了。Looper内部维护一个MessageQueue。
这时候整个的MessageQueue通过Looper跟线程关联上了,这样不同的线程就不能访问其他的消息队列了

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

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

而从MessageQueue队列中获取消息,要通过Looper.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;
        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;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        final long traceTag = me.mTraceTag;
        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }
        try {
           //处理消息
            msg.target.dispatchMessage(msg);   
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }
         //回收消息      
        msg.recycleUnchecked();

通过代码可以看出,loop()方法实际上就是创建了一个for的死循环,然后从消息队列中逐个获取消息(当没有消息时,queue.next()会阻塞,直到有消息才继续执行),最后处理消息的过程。
总结一下:Looper通过Looper.prepare()来创建Looper对象,保存在ThreadLocal中,然后通过Looper.loop()开启循环,来进行消息的分发

msg.target.dispatchMessage(msg)也就是Handler.dispatchMessage(msg)

 /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    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();
    }

dispatchMessage(msg)方法其实只是一个分发的方法,首先会判断msg.callback是否为空,(.callback其实是一个Runnable对象,在上面的使用方法中有写)如果不为空,就执行handleCallback方法,而handleCallback方法里面其实调用的就是线程的run()方法。如果为空,将执行handleMessage来进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值