Handler的源码分析

handler的原理

android的handler机制可谓是最常用的机制之一了,而它的原型就是 linux进程间的通信.下面简单介绍:
1.通讯原型:
linux进程间的通信:linux管道通讯,管道其实就是个特殊的文件,该文件有两个描述符(操作文件的句柄(引用)),读的描述符,写的描述符主线程拿着读的描述符等待读取数据,子线程拿着写的描述符开始写数据,写完数据之后通知拿着读描述符的主线程,主线程唤醒,开始轮询取消息,处理消息,如果没有消息中断(阻塞)

2.handler机制原理:
handler发送Message 唤醒Looper器,轮询器开始遍历MessageQueue,轮询取消息,处理消息

下面直接上源码,注意注释

首先ActivityThread.java会创建looper并且会执行loop()开始轮询,如果此时消息队列中无消息,则会阻塞(JNI), 而handler向消息队列发送消息(此时无消息,且looper处于阻塞状态),则由消息队列的next()来唤醒(JNI)looper,经一系列方法最终调用handleMessage().


本文分三个线
首先是ActivityThread准备Looper和预先的准备;
是handler的sendMessage()发送消息;
最后是looper轮询去消息并执行;


ActivityThread

ActivityThread类中初始化,应用程序运行之前执行,main方法如下:

  //主线程
     public static final void main(String[] args) {
        ...
        //轮询器的初始化
        Looper.prepareMainLooper();
        ...
        //轮询器开始取消息
        Looper.loop();
    }

1.new Handler()

public Handler() {
                    //1.
                    this(null, false);
                }
                //2. 
                public Handler(Callback callback, boolean async) {

                        ...
                        //获取轮询器
                        //3. 看4步

                        //9.
                        mLooper = Looper.myLooper();
                        if (mLooper == null) {
                            throw new RuntimeException(
                                "Can't create handler inside thread that has not called Looper.prepare()");
                        }
                        //10. 获取消息队列MessageQueue
                        mQueue = mLooper.mQueue;
                        mCallback = callback;
                        mAsynchronous = async;
                    }
                //4.Looper.myLooper();
                       return sThreadLocal.get();
                //5. 赋值Looper(主线程)
                        ActivityThread
               // 6.  main()
                        Looper.prepareMainLooper();
               //7. Looper.prepareMainLooper();
                         prepare(false);
                        synchronized (Looper.class) {
                            if (sMainLooper != null) {
                                throw new IllegalStateException("The main Looper has already been prepared.");
                            }
                            //获取 
                            sMainLooper = myLooper();
                        }
               //8.  prepare(false);
                             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器对象和消息队列
获取Looper对象主要是为了获取消息队列
looper对象主要是靠ActivityThread存进去的
(prepareMainLooper()–>prepare(false)–>sThreadLocal.set(new Looper(quitAllowed));)
而获取looper对象是Looper.myLooper()–>sThreadLocal.get();

2. Message

1. new Message 
     public Message() {
            }

2. Message.obtain()  

         public static Message obtain() {
                synchronized (sPoolSync) {
                    if (sPool != null) {// sPool  Message
                        Message m = sPool;
                        sPool = m.next;
                        m.next = null;
                        sPoolSize--;
                        return m;
                    }
                }
                return new Message();
            }
            方法重载很多,每个方法的本质都会走上面代码

    3. mHandler.obtainMessage()

             Message.obtain(this);  //把handler做绑定,(this就是handler)

3. Looper
4. MessageQueue

ThreadLocal

线程的本地变量,每个线程都可以往tl里set值 ,取的时候根据线程的标记取出对应每个线程set的值


发送消息
1.  Message类中的 sendToTarget

        public void sendToTarget() {
            target.sendMessage(this);(看2)
        }


2. mHandler.sendMessage(msg);

        public final boolean sendMessage(Message msg)
        {
            //1.
            return sendMessageDelayed(msg, 0);
        }
        //2. sendMessageDelayed(msg, 0);
         public final boolean sendMessageDelayed(Message msg, long delayMillis)
            {
                if (delayMillis < 0) {
                    delayMillis = 0;
                }
                //3.
                return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
            }
        //4.sendMessageAtTime
             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;
                }
                //5.  把handler绑定到message并且把消息放到消息队列并且按时间排序
                return enqueueMessage(queue, msg, uptimeMillis);
            }
        //6.enqueueMessage(queue, msg, uptimeMillis)

                private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
                    //把Handler绑定到Message的target属性
                    msg.target = this;//this Handler对象(考虑到new Message()的情况,保险)
                    if (mAsynchronous) {
                        msg.setAsynchronous(true);
                    }
                    //7. 把消息放到消息队列并且按时间排序
                    return queue.enqueueMessage(msg, uptimeMillis);
                }
        //8. MessageQueue的queue.enqueueMessage
                  boolean enqueueMessage(Message msg, long when) {
                        ...

                        synchronized (this) {
                            ...
                            msg.when = when;//message的发送时间
                            Message p = mMessages;//mMessages MessagQueue的属性Message类型
                            boolean needWake;
                            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 {
                                // Inserted within the middle of the queue.  Usually we don't have to wake
                                // up the event queue unless there is a barrier at the head of the queue
                                // and the message is the earliest asynchronous message in the queue.
                                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                                //消息插入的位置
                                Message prev;
                                for (;;) {
                                    prev = p;
                                    p = p.next;
                                    if (p == null || when < p.when) {
                                        break;
                                    }
                                    。。。唤醒逻辑
                                }
                                msg.next = p; // invariant: p == prev.next
                                prev.next = msg;
                            }

                            // We can assume mPtr != 0 because mQuitting is false.
                            if (needWake) {
                                nativeWake(mPtr);
                            }
                        }
                        return true;
    }

取并处理消息
1. Looper.loop();//轮询
2. 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.");
            }
            //从轮询器中获取消息队列和Handler 的queue 是同一个消息队列
            final MessageQueue queue = me.mQueue;

            ...

            for (;;) {
                //MessageQueue的next方法
                //1. 取消息看2
                Message msg = queue.next(); // might block
                //处理消息
                //3. 处理消息看4
                msg.target.dispatchMessage(msg);

                ...
                //回收消息 kan 6
                msg.recycle();
            }
        }

        // 2. MessageQueue的next方法(已经做了阻塞的处理)
                 Message next() {
                    int pendingIdleHandlerCount = -1; // -1 only during first iteration
                    int nextPollTimeoutMillis = 0;
                    for (;;) {
                        if (nextPollTimeoutMillis != 0) {
                            Binder.flushPendingCommands();
                        }

                        // We can assume mPtr != 0 because the loop is obviously still running.
                        // The looper will not call this method after the loop quits.
                        nativePollOnce(mPtr, nextPollTimeoutMillis);

                        synchronized (this) {
                            // Try to retrieve the next message.  Return if found.
                            final long now = SystemClock.uptimeMillis();
                            Message prevMsg = null;
                            Message msg = mMessages;

                        //不阻塞的话取出消息
                            if (msg != null) {
                                if (now < msg.when) {
                                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                                } else {
                                    // Got a message  取消息.
                                    mBlocked = false;
                                    if (prevMsg != null) {
                                        prevMsg.next = msg.next;
                                    } else {
                                        mMessages = msg.next;
                                    }
                                    msg.next = null;
                                    if (false) Log.v("MessageQueue", "Returning message: " + msg);
                                    msg.markInUse();    //标记消息已被用过,一班不会发生
                                    return msg;
                                }
                            } else {
                                // No more messages.
                                nextPollTimeoutMillis = -1;
                            }

                            // Process the quit message now that all pending messages have been handled.
                            if (mQuitting) {
                                dispose();
                                return null;
                            }

                            // If first time idle, then get the number of idlers to run.
                            // Idle handles only run if the queue is empty or if the first message
                            // in the queue (possibly a barrier) is due to be handled in the future.
                            if (pendingIdleHandlerCount < 0
                                    && (mMessages == null || now < mMessages.when)) {
                                pendingIdleHandlerCount = mIdleHandlers.size();
                            }
                            if (pendingIdleHandlerCount <= 0) {
                                // No idle handlers to run.  Loop and wait some more.
                                mBlocked = true;
                                continue;
                            }

                            if (mPendingIdleHandlers == null) {
                                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                            }
                            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
                        }

                        // Run the idle handlers.
                        // We only ever reach this code block during the first iteration.
                        for (int i = 0; i < pendingIdleHandlerCount; i++) {
                            final IdleHandler idler = mPendingIdleHandlers[i];
                            mPendingIdleHandlers[i] = null; // release the reference to the handler

                            boolean keep = false;
                            try {
                                keep = idler.queueIdle();
                            } catch (Throwable t) {
                                Log.wtf("MessageQueue", "IdleHandler threw exception", t);
                            }

                            if (!keep) {
                                synchronized (this) {
                                    mIdleHandlers.remove(idler);
                                }
                            }
                        }

                        // Reset the idle handler count to 0 so we do not run them again.
                        pendingIdleHandlerCount = 0;

                        // While calling an idle handler, a new message could have been delivered
                        // so go back and look again for a pending message without waiting.
                        nextPollTimeoutMillis = 0;
                    }
                }

        //4. msg.target.dispatchMessage(msg);
            msg.target  handler
            dispatchMessage 是handler的方法

             public void dispatchMessage(Message msg) {
                    if (msg.callback != null) {
                        //回调 看5
                        handleCallback(msg);
                    } else {
                        if (mCallback != null) {
                            if (mCallback.handleMessage(msg)) {
                                return;
                            }
                        }
                        //处理消息 主线程调用
                        handleMessage(msg);
                    }
                }
        //5. 回调
                    handleCallback(msg);

                private static void handleCallback(Message message) {
                    message.callback.run();//主线程中调用
                }       

        //6. 回收消息(把消息放到消息池中) msg.recycle();
                public void recycle() {
                    //7.
                    clearForRecycle();

                    synchronized (sPoolSync) {
                        if (sPoolSize < MAX_POOL_SIZE) {
                            next = sPool;
                            sPool = this;
                            sPoolSize++;
                        }
                    }
                }
      //7. clearForRecycle();
                /*package*/ void clearForRecycle() {
                    flags = 0;
                    what = 0;
                    arg1 = 0;
                    arg2 = 0;
                    obj = null;
                    replyTo = null;
                    when = 0;
                    target = null;
                    callback = null;
                    data = null;
            }

其他的小问题:
1.mHandler 是消息队列的touch头指针 ; msg.target 是Handler
2.为什在子线程中new Handler()会报错
因为子线程中没有Looper,所以只能在主线程中new Handler()
new Handler(){
Looper.myLooper();//子线程无Looper,子线程执行报异常
}

根据源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值