Handler机制流程梳理、源码分析

Handler机制流程梳理、源码分析

在上几篇文章中我们已经介绍过了Android中使用线程、线程池以及异步任务的方法,通过对AsyncTask的源码分析,我们知道它的底层实现就是通过线程以及Handler机制来完成的,Handler机制也是Android提供的一种针对异步操作的方式,可以实现主线程与子线程之间的通信,接下来本篇文章就针对Android中的Handler机制进行解剖,总结。

Handler机制的相关类

首先我们看一下Handler的重载的构造方法,其中无参的构造方法又默认调用下面的这个构造方法。而这个构造方法中又做了那些事情呢?我们继续看,首先通过Looper.myLooper()初始化Looper对象mLooper,然后又初始化了MessageQueue对象mQueue。加上Handler发送的消息,整个Handler机制涉及到了如下几个类:

Handler、Looper、MessageQueue、Message

 public Handler(Callback callback, boolean async) {
        //前面省略
        mLooper = Looper.myLooper();//获取Looper,**注意不是创建Looper**!
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//创建消息队列MessageQueue
        mCallback = callback; //初始化了回调接口
        mAsynchronous = async;
    }

那么这几个类的作用究竟是什么呢,他们之间又有什么关系,我们接下来继续看。

Looper与MessageQueue

使用过Handler的同学们知道,在主线程使用Handler的时候,并没有手动的创建Looper以及MessageQueue,实际上在主线程ActivityThread中,系统已经为我们创建了,源码如下,在ActivityThread的main方法中:

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        //其他代码省略...
        Looper.prepareMainLooper(); //初始化Looper以及MessageQueue

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop(); //开始轮循操作

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

那么这几个方法中都做了些什么,我们接下来看一下。

Looper.prepareMainLooper():

这个方法主要是初始化Looper对象以及MessageQueue对象,首先执行了Looper的prepare(boolean quitAllowed)方法:

public static void prepareMainLooper() {
        prepare(false);//
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

在这个方法中,首先判断了是否已经创建了Looper对象,没有的话就会调用Looper的构造方法,并set给sThreadLocal。
已经创建过得话,即if (sThreadLocal.get() != null),就会抛异常,这也体现了,一个线程里最多只能创建一个Looper对象以及一个MessageQueue(主线程已为我们创建好,而子线程默认没有)。

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

Looper与MessageQueue以及当前线程的绑定:

再看Looper的构造方法,在构造方法中创建了消息队列MessageQueue,并且绑定了当前的线程。

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

Looper.loop():

首先里面调用了sThreadLocal.get()获得刚才创建的Looper对象,后面进入一个死循环,从消息队列不断的取消息,如果有消息则交给Handler进行dispatchMessage,否则进入阻塞状态。

public static void loop() {
        final Looper me = myLooper();//里面调用了sThreadLocal.get()获得刚才创建的Looper对象
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }//如果Looper为空则会抛出异常
        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;
            }

            // 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,详见后面Message的部分,Handler开始dispatchMessage(msg)
            //后面代码省略.....

            msg.recycleUnchecked();
        }
    }

Message

Message,即消息,实现了Parcelable接口,Message是怎么携带“消息内容”的呢?Message里面有4个变量,3个int型,what,arg1,arg2,以及一个Object型的变量obj,其中我们可以将需要传递的数据赋值obj,而在handleMessage方法中,就可以拿到我们所需要的数据进行处理了,而what可以作为一个标识符,来判断接收到的message对象里面存储的是什么数据类型,这样就可以针对不同的数据分别作出相应的操作了。

创建Message对象

为了发送消息,我们首先要获得Message对象,有些同学可能说了直接new一个出来就好了?实际上new出来也是可以的,但是有一种更好的方式。Message的获得由2种方式,一种是Handler的obtainMessage()方法,另一种是Message类的静态方法,Message.obtain()。

  public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

通过看源码我们可以发现,Handler的obtainMessage()方法,内部就是调用了Message的obtain(Handler)方法,那么这么创建有什么好处呢?首先我们知道,直接通过new创建每次都会创建一个新的对象,这样不停的创建新的对象,会消耗资源。而使用Message.obtain()方法,第一次获取的时候,sPool为空,所以直接返回一个new Message()对象。

 public static Message obtain(Handler h) {
        Message m = obtain();//调用重载的obtain方法
        m.target = h;//并绑定的创建Message对象的handler

        return m;
    }

public static Message obtain() {
        synchronized (sPoolSync) {//sPoolSync是一个Object对象,用来同步保证线程安全
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

而在上面Looper的源码中,当handler进行dispatchMessage方法后,就会对message进行回收,这时候进入 recycleUnchecked()方法中,可以看到将使用过得message对象赋值给了sPool,这时候sPool就不为空了,而再次调用message.obtain()方法的时候,就避免了直接创建新的message对象,而是可以从回收的取出一个来进行复用。

 void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

因此在创建Message对象的时候,任何时候都推荐使用上面的2种方法,而不是直接使用new关键字来进行创建。

Message和Handler的绑定

通过这段代码,可以看到通过obtainMessage()创建的时候,就将Handler赋给了Message对象的target,完成了绑定。

 public static Message obtain(Handler h) {
        Message m = obtain();//调用重载的obtain方法
        m.target = h;//并绑定的创建Message对象的handler

        return m;
    }

那么通过Message.obtain()这个无参的方法创建的Message对象,是怎么和Handler完成绑定的呢?
我们可以先看一段Handler的源码,在发送消息的时候,sendMessage通过一系列的调用,最终会调用enqueueMessage方法,在这里,就可以看到,发送的message即msg,在发送的时候,将this即hanlder对象与Message绑定到了一块。

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//将handler与message完成绑定
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

Handler

我们通过上面的源码,已经知道了Looper将Message对象从MessageQueue取出来,最终交给了Handler进行派发,下面我们来看一下Handler的源码,了解一下是怎么实现的。

Handler的构造方法:

在主线程通过无参的构造方法创建,而无参的构造方法调用重载的构造方法,并在此拿到了这个线程中对应的Looper以及MessageQueue,这样就完成了Handler与Looper、MessageQueue之间的绑定。

public Handler() {
        this(null, false); //无参的构造方法调用重载的构造方法
    }

public Handler(Callback callback, boolean async) {
        //此处代码省略...

        mLooper = Looper.myLooper();//拿到了当前线程的绑定的Looper
        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;
    }

Handler发送消息:

Handler发送消息的重载方法很多,但是主要只有2种。
- sendMessage(Message)

sendMessage方法通过一系列重载方法的调用,sendMessage调用sendMessageDelayed,继续调用sendMessageAtTime,继续调用enqueueMessage,继续调用messageQueue的enqueueMessage方法,将消息保存在了消息队列中,而最终由Looper取出,交给Handler的dispatchMessage进行处理。

我们可以看到在dispatchMessage方法中,message中callback是一个Runnable对象,如果callback不为空,则直接调用callback的run方法,否则判断mCallback是否为空,mCallback在Handler构造方法中初始化,在主线程通直接通过无参的构造方法new出来的为null,所以会直接执行后面的handleMessage()方法。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {//callback在message的构造方法中初始化或者使用handler.post(Runnable)时候才不为空
        handleCallback(msg);
    } else {
        if (mCallback != null) {//mCallback是一个Callback对象,通过无参的构造方法创建出来的handler,该属性为null,此段不执行
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);//最终执行handleMessage方法
    }
}

 private static void handleCallback(Message message) {
        message.callback.run();
    }


  • post(Runnable)

post(Runnable)方法,实际上执行的是sendMessageDelayed方法,先将Runnable对象赋给了Message对象中的callback,然后通过sendMessage方法向下传递,中间过程同上面的相同,在dispacthMessage方法中,调用了handleCallback方法,在handleCallback方法中,最终执行Runnable对象的run()方法。
 private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();//将Runnable对象封装成Message对象
        m.callback = r;
        return m;
    }

 public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);//sendMessage方法继续发送
    }
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {//callback不为空,调用handleCallback方法
        handleCallback(msg);
    }
}
private static void handleCallback(Message message) {
        message.callback.run();// message.callback即上面的post()中的Runnable对象,最终执行了run方法。
    }

Handler处理消息:

在handleMessage(Message)方法中,我们可以拿到message对象,根据不同的需求进行处理,整个Handler机制的流程就结束了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值