Handler机制源码解析

ぃ、小莉子 提交于 2020-12-17 06:29:26

 

不多废话上图:

 

 

简单来说handler流程就是handler 在消息池中获取msg 并发送给 MQ, 再由Looper进行轮询在MQ中得到待处理的msg交由handler进行 handleMessage(...);

 

这里主要涉及到了四个核心类: Message  Handler   MessageQueue   Looper

那么下面来看看源码里面是怎么实现的:

1.

Message用来携带数据的载体

public int what; //标识

public int arg1; //携带int类型数据

public int arg2; //携带int类型数据

public Object obj;//携带任意对象数据

long when; //保存要被处理的时间点

Handler target; //处理消息的handler

Runnable callback; //处理消息的回调器对象

Message next; //用来保存引用的下一个message(才能形成链表)

private static Message sPool; //存储处理过的消息的池 //在需要Message对象时复用

其中还有recycle()方法 Looper轮询过程中中会用到

2. 

Handler进行消息的发送处理源码里面主要调用了如下几个方法:

sendMessage(Message msg)

public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);//那我们再去看看另一个方法
}


sendEmptyMessage(int what)

public final boolean sendEmptyMessage(int what)
{
    return sendEmptyMessageDelayed(what, 0);//和上面的一样 返回了一个延迟方法,那我们去看看这个方法;
}


sendMessageDelayed(Message msg, long delayMillis)

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
   ...
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);//返回了atTime的方法,再继续:


sendMessageAtTime(Message msg, long uptimeMillis)


public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
   ...
    return enqueueMessage(queue, msg, uptimeMillis);//再去找这个方法 
}


会发现所有的最后都是调用了这个方法:

sendMessageAtTime();//当前时间+延迟时间

而这个方法中调用了 enqueueMessage(),那么我们来看看这里面到底实现了什么东西:

//源码

msg.target = this;
if (mAsynchronous) {
    msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);

里面是调用了MQ中的同名方法,下面就看看MessageQueue中主要的方法;

(handler中还有其他的关键方法 dispatchMessage(), Looper中会用到)

 

3.  MessageQueue:

看一看源码中的enqueueMessage()方法;

boolean enqueueMessage(Message msg, long when) {
    ...

        msg.when = when;  //将消息被处理的时间保存在msg上
        
        //将msg对象保存到mMessages链表中一个合适的位置,msg会和mq中的msg的时间when进行比较,
        当小于其中一个的时候会插入当前的位置;
        Message p = mMessages;  
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            msg.next = p; 
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        
       //调用c或c++唤醒处理等待状态下的程序,防止阻塞
        if (needWake) {  
            nativeWake(mPtr);
        }
    }
    return true;
}

可以发现里面主要做了三件事:

msg.when = when; //将消息被处理的时间保存在msg

//msg对象保存到mMessages链表中一个合适的位置

 

nativeWake(mPtr); //唤醒处理等待状态下的程序

//不是通过wait()来实现的而是通过C/C++的代码来实现的不会阻塞主线程


    还有一个主要方法: next(), 很明显就是进行查询的,Looper中会用到


4. Looper

其中主要有 loop() 

static void 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;    //拿到消息队列

    // 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(); // 获取到mq中的msg
        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
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        msg.target.dispatchMessage(msg);  //调用msg中的target(Handler对象)的dispatch...(msg)方法

        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();//清除回收处理过的msg所携带数据和标识等,并将msg保存到消息池中
    }
}

 可以看到loop()里面主要是调用了其他三个类中的方法:

    a. mq.next();从mq中获取msg

    b.handler.dispatchMessage(); handler进行分发消息 (源码里可以看出 此方法中有三个优先级的回调,而我们常用的是 handleMessage(). 其实第一级是msg.callBack, 第二级是 handler中的CallBack{},最后才是handleMessage(),但一般情况下前两者为为空,所以通常我们直接处理handleMessage()方法,代码如下

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

)

    c.msg.recycleUnchecked(); 回收ms;


写的不好,主要目的是给自己复习一下,想系统地了解请点击如下链接:

http://blog.csdn.net/lmj623565791/article/details/38377229

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!