美文网首页
一起谈谈-Handler

一起谈谈-Handler

作者: AntCoding | 来源:发表于2019-03-12 22:01 被阅读0次

    基础讲解

    看了不少的技术大牛分享的博客,里面从各个侧重点讲解Handler,俗话说"乱花渐欲迷人眼,浅草才能没马蹄";所以我选择拜读一次源码,从源码找寻答案只用这样才能才能记一下它的机制;

    注意: 由于代码的分析需要在某一段代码上有特殊讲解,我会将理解写在带片段中

    纸上得来终觉浅 绝知此事要躬行.那我们就开始吧!

    摘要

    探究Handler我决定从以下几个方面
    • 案例列举
    • Handler的创建
    • Handler消息发送
    • Handler消息处理

    1. 案例列举

    在我们开发程序过程中肯定少不了使用Handler,所以我在此处就不做过多的解释了,直接上代码

    private Handler mineHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {​​
                super.handleMessage(msg);
    ​            switch (msg.what) {
                  case Flag:        //此处对msg.what做识别判断,用于处理不同的业务
                  break;
                }
            }
        };
    ​
    Message message = Message.obtain();
    message.what = AIDL_ACTION;
    message.obj = ERROR_INFO;​
    mineHandler.sendMessage(message);​
    

    2. Handler的创建

    源码分析
    //我们创建Handler的方式
    ​private Hanlder mineHandler=new Handler(){};
    ​//--------------------------------------------------
    //源码的创建过程
    public class Handler {​​​
       ...​
       ​public Handler() {
           this(null, false);
       }
    ​
       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()");
           }
           //关联消息队列​
           mQueue = mLooper.mQueue;​
           mCallback = callback;
           mAsynchronous = async;
       } 
       ...​​​​
    ​}​
    
    2.1 此处我们可以看到在Handler过程中会从ThreadLocal中获取当前线程的Looper对象,当Looper为Null会抛出一个RuntimeException异常
    2.1.1 为何我们在UI线程中使用Hanlder并没有创建Looper为什么会不报错呢?

    因为早在ActivityThread中main方法函数就已经为我们创建出了Looper对象

    public final class ActivityThread{
       public static void main(String[] args) {
        ...
        //获取当前线程的Looper​
        Looper.prepareMainLooper();
        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");
     }
    ​​​}
    
    2.1.2 如果我们在其他线程中使用Handler需要如何做呢?

    由于在Handler创建过程中会将当前线程的Looper对象赋给成员变量mLooper,并会对其判Null,若当前线程中不存在Looper对象则会抛出一个RuntimeException异常,所以在其他线程使用Handler必须先初始化一个Looper对象,代码如下:

    new Thread(){
           Handler handler=null;
           public void run(){
                //1.为当前线程创建Looper,并且会绑定到ThreadLocal中
                Looper.prepare();
                handler=new Handler();
                //2.启动消息队列
                Looper.loop();
           } ;
     }.start()
    

    3. Handler消息发送

    3.1基础用法

    • post(Runnable)
    • postDelayed(Runnable, long)
    • postAtTime(Runnable, long)
    • sendEmptyMessage(int)
    • sendMessage(Message)
    这些方法是向MessageQueue消息队列中添加添加消息,通过上面方法中的传递参数我们可以看出,Handler发送的消息分为两种类型即:
    • Runnable类型
    • Message类型
    事实上由post方式发出的Runnable对象最后都被封装成Message对象,接下来我们就从以上方法中找出两个有代表性的方法做源码讲解根据发送消息的类型在区分
    3.1.1 post(Runnable)源码分析
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    ​
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
    ​​
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }​​
    ​
    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);
    }​​
    
    3.1.1.1.在这一部分代码中我们发现post函数方法中调用getPostMessage(r)将Runnable封装成了一个Message,最终的实现是在sendMessageAtTime函数方法中调用 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);
    }
    
    3.1.1.2.最终通过MessageQueue的实例queue调用方法函数enqueueMessage(msg, uptimeMillis)实现
    boolean enqueueMessage(Message msg, long when) {
       
        synchronized (this) {
            //判断当前线程是否已关闭​
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                //​消息回收
                msg.recycle();
                return false;
            }
             msg.markInUse();
             msg.when = when;
             Message p = mMessages;
             boolean needWake;
    ​        //若此判断成功,说明队列中没有数据存在,我们将会把传进来的msg放入队列首部
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {  //判断失败,说明队列中已存在数据,则将传进来的msg插入到队列中
                 //在队列中间插入,通常我们不需要醒来事件队列,除非有一个阻塞的队列和最早的消息存在于异步消息队列中。
                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;
            }
            //是否需要唤醒
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
    
    3.1.1.3.通过一个for死循环遍历MessageQueue中的message,若当前msg.when小于MessageQueue中某一条message.when时,就将msg插入到MessageQueue队列中该条message的后面.至此实现向MessageQueue队列中添加消息
    3.1.2 sendMessage(Message)源码分析
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    ​public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }​
    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);
    }​​
    ​
    
    我们发现最终的调用依然进入了sendMessageAtTime方法函数进入到MessageQueue类的enqueueMessage(msg, uptimeMillis)实现的往下就进行过多的分析,同上面的调用步骤一致
    不单单是这两个方法的调用一致,以下方法的调用都一致的最后都进入到sendMessageAtTime方法函数进入到MessageQueue类的enqueueMessage(msg, uptimeMillis)实现的
    • post(Runnable)
    • postDelayed(Runnable, long)
    • postAtTime(Runnable, long)
    • sendEmptyMessage(int)
    • sendMessage(Message)

    • |---> sendMessageDelayed(Message, long)
    • |--- | ---> sendMessageAtTime(Message, long)

    4. Handler消息处理

    Handler处理的是MessageQueue队列中获取的Message,那么是谁从MessageQueue获取的Message呢?答案是肯定的是Looper,那Looper又是如何获取的呢我们接着分析源码

    4.1. 在声明Handler的时候源码会获取当前线程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;
    }
    
    4.2. Looper.loop()开启消息队列的轮询
    我们在其他线程创建Handler的时候会先创建一个Looper然后调用Looper中的静态函数loop()方法开启队列轮询
    new Thread(){
           Handler handler=null;
           public void run(){
                //1.为当前线程创建Looper,并且会绑定到ThreadLocal中
                Looper.prepare();
                handler=new Handler();
                //2.启动消息队列
                Looper.loop();
           } ;
     }.start()
    
    那为什么我们在UI线程创建了Handler之后不需要调用Looper的静态函数loop()方法开启队列轮询呢?
    答案就在源码的ActvityThread类中
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        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");
    }
    
    原来在ActivityThread创建之初,就已经为程序开启了消息队列轮询了,所以洒洒水啦! 我们的系统已经为你做好了一切前提配置了
    4.3. 那么Looper.loop()究竟做了哪些事情呢? 让我们源码中寻找答案吧!
    public static void loop() {
        //首先从ThreadLocal获取Looper对象这是必须的​
        final Looper me = myLooper();
        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死循环果然霸气十足​
        for (;;) {
            Message msg = queue.next(); // might block
            //若msg为Null,那就没必要再轮询了 直接return就够了​
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            //他的日志必须在本地变量中,以防UI事件设置日志记录器
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
                //上面解释了那么多,都是前期铺垫;这是我们的重点​
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
    ​
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }
            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
            //确保在调度过程中线程的标识没有损坏
            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();
        }
    }
    
    4.4. 经过了一段代码的分析,最终我们找到了分析重点 函数方法 -> msg.target.dispatchMessage(msg)
    首先我们msg是Message实例对象,而target是Message中成员变量,那target是谁呢?
    /*package*/ Handler target;​ 
    
    原来它就是Handler啊,通过这种调用我们成功的将Handler与Looper关联到了一起
    4.5.接下来我们就来分析msg.target.dispatchMessage(msg)方法吧 即Handler中的dispatchMessage(msg)
    public void dispatchMessage(Message msg) {
        //优先处理msg中callback操作​
        if (msg.callback != null) {
            handleCallback(msg);
        } else { //若msg中无callback操作,执行此操作
            ​//再判断Handler是否有callback操作
            if (mCallback != null) {
                //若执行完操作返回的值为true,则return;
                //若返回false则继续执行handleMessage操作
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
           ​ //优先级最低的执行方法
            handleMessage(msg);
        }
    }
    
    4.5.1 handleCallback(msg);
    private static void handleCallback(Message message) {
        message.callback.run();
    }
    
    4.5.2 mCallback.handleMessage(msg)
    public interface Callback {
       /**
        * @param msg A {@link android.os.Message Message} object
        * @return True if no further handling is desired
        */
       public boolean handleMessage(Message msg);
    }`
    
    4.5.3 handleMessage(msg);
    public void handleMessage(Message msg) {
    }
    
    4.5.5 总结

    这三个方法都是在外部实现的,也就是由我们具体的业务决定的

    至此我就谈完了对Handler消息的处理的理解!

    汇总

    • handler创建时获取当前线程的lopper,并关联了looper的消息队列MessageQueue
    • handler通过post 或 sendMessage相关方法好说将消息发出,并添加到MessageQueue消息队列中
    • Looper通过调用loop方法函数,轮询MessageQueue不断地获取Message,由于Message中存在Handler的实例变量,通过此变量我们将消息回传到Handler中,经用户的实现抽象方法和接口完成对消息的处理!

    This ALL! Thanks EveryBody!

    相关文章

      网友评论

          本文标题:一起谈谈-Handler

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