Handler,Looper,Message,MessageQueue源码解析带你深入理解

------------------------------------------Handler源码详解------------------------------------
    
    final MessageQueue mQueue;//这个消息队列也是创建Handler对象所在的消息队列
    final Looper mLooper;//这里的Looper对象是它创建Handler对象所在的线程对应的Looper
    final Callback mCallback;
    final boolean mAsynchronous;
    IMessenger mMessenger;
    
    public Handler(Callback callback, boolean async) {
      
        mLooper = Looper.myLooper();//获取当前线程对应的Looper对象
         ...//如果mLooper为null抛出异常
        mQueue = mLooper.mQueue;//获取Looper对象上的消息队列
        mCallback = callback;
        mAsynchronous = async;
    }
    
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    
    //这个方法是你想对获取到的消息做何处理,需要你重写
    public void handleMessage(Message msg) {
    }
    
    /**
     * Handle system messages here.进行系统消息分发
     */
    public void dispatchMessage(Message msg) {//你的消息都在队列中都是调用这个方法来给handler处理
        if (msg.callback != null) {//如果你的msg中的callback方法不为空(post发送)它会调用如下方法来处理
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    
     private static void handleCallback(Message message) {//这是它是运行在主线程中
        message.callback.run();
    }
    
     public final Message obtainMessage()
    {
        return Message.obtain(this);
    }
    
    
     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {//在指定事件分发消息
        MessageQueue queue = mQueue;
        .....//这里如果queue为null直接抛异常
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    
     public final boolean sendMessageAtFrontOfQueue(Message msg) {//将消息插入消息队列的前面
        MessageQueue queue = mQueue;
         .....//这里如果queue为null直接抛异常
        return enqueueMessage(queue, msg, 0);
    }
    
    //消息进行发送最终会调用这个方法
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//从这里可以看出它将自己(Handler对象)设置都Message中的target字段上
        .....
        return queue.enqueueMessage(msg, uptimeMillis);//这里调用消息队列上的插入消息的方法把消息插入进去
    }
    
    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;
    }
    
   


总结:
从分析可知它发送消息其实就是调用MessageQueue的插入消息方法(enqueueMessage(queue, msg, uptimeMillis);---->queue.enqueueMessage(msg, uptimeMillis);)。
而MessageQueue的由来先是通过myLooper来获取当前线程的Looper对象。再通过mLooper.mQueue获取上面的消息队列
而初始化那些数据是在构造方法中执行的,从这里可知Handler的创建是在它所在线程中进行调用创建初始化


------------------------------Looper源码分析----------------------------
    sThreadLocal.get() will return null unless you've called prepare().
   //这里是设计巧妙把线程和Looper对象关联在一起
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
   //保存主线程中的looper对象
    private static Looper sMainLooper;  // guarded by Looper.class


  //消息队列
    final MessageQueue mQueue;//这里保存消息队列,它的创建就是Looper构造方法的创建
    
    final Thread mThread;
    
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//创建Looper时就创建MessageQueue对象
        mThread = Thread.currentThread();
    }


  public static void prepare() {
        prepare(true);
    }
       
      //这个方法是用来把创建looper对象放入到调用的线程中
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {//如果该线程中存在looper对象再次调用报错
            throw new RuntimeException("Only one Looper may be created per thread");
        }
         
         //把looper对象放入到ThreadLocal中使其和调用线程关联在一起
        sThreadLocal.set(new Looper(quitAllowed));
    }


        //用来获取当前线程所对应的looper对象
public static  Looper myLooper() {
        return sThreadLocal.get();
    }


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


  public static void loop() {
        final Looper me = myLooper();//获取当前线程对应的looper对象
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//获取looper对象中的消息队列
              ........
        for (;;) {
            Message msg = queue.next(); // might block它是个阻塞的方法它用来从消息队列中获取下一条消息
            if (msg == null) {
                return;
            }
            msg.target.dispatchMessage(msg);//获取到消息就进行分发(target为Handler)
              .......
        }
    }
 
public static  MessageQueue myQueue() {
        return myLooper().mQueue;
        }


总结:
prepare方法:它是将线程和消息存放到sThreadLocal中(注意sThreadLocal是静态变量,它是所有Looper对象共享) 


-------------------------MessageQueue源码---------------------------
//这里可以看出MessageQueue中其实只存Message的头(原因Message它是个类似节点结构) 
  Message mMessages;
 
MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }
   
  //这个消息是从消息队列中取出消息
  Message next() {
            ........
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
              
                Message prevMsg = null;//它用来保存要获取消息的前一个节点
                Message msg = mMessages;//它用来寻找要获取的节点
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                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;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
          ......
    }
    
    
    //这个方法是将消息插入到消息队列中
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {//从这里可以看出要想消息可就添加到消息队列中消息必须要关联到Handler对象
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }


        synchronized (this) {//这里可以看出它添加消息是同步方法
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                msg.recycle();
                return false;
            }


            msg.markInUse();
            msg.when = when;
            Message p = mMessages;//它用来寻找要插入消息的位置
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {//如果消息是第一个消息或者此消息不能等或者这个消息等待时间比p(头部消息)消息小
                // New head, wake up the event queue if blocked.
                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) {//结束条件消息队列到了末尾或此消息等待时间小于p
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next 将msg插入到pre和p之间
                prev.next = msg;
            }


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




总结:
next方法内部思路:
       它是利用一个标记来查找消息队列中此时的消息是否是要找的消息。找到后就修改它们之间的关系前取出的前一个节点的next指向取出节点的后一个节点
enqueueMessage方法内部思路:
       在插入消息前它会先判断要插入的消息是否关联上了Handler对象如果没有不进行插入操作。
       如果有,它会根据插入消息的时间和消息队列中消息插入时间来找到合适的位置(注意它是等待时间越小会越放在消息队列的前面)
    
---------------------------------------Message源码--------------------------------
 
    public int what;
    public int arg1; 
    public int arg2;
    public Object obj;
    public Messenger replyTo;//这里是为了服务端与客户端进行进程通讯用的
    int flags;
    long when;
    Bundle data;
    Handler target;//为什们消息可以给指定的target处理这里就可以看出它自己保存了Handler对象
    Runnable callback;
    
     private static Message sPool;//这个很重要它相对与一个池用来从用Message对象(设置为静态属性所以对象都可以实现共用)
     
    
     Message next;//这里可以看出它保存了下一个节点
     private static final Object sPoolSync = new Object();//这里设置一个锁对象
    
     //这里又是个代理模式
   public void sendToTarget() {
        target.sendMessage(this);
    }
    
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {//先看池中是否有可用的Message对象
                Message m = sPool;//从池中移出一个Message对象并返回
                sPool = m.next;//池的开头Message对象变为下一个
                m.next = null;//将要返回的Message对象的next设置为空使其不和其他Message对象联系
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    
    
    public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        m.sendingUid = orig.sendingUid;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;


        return m;
    }
    
    //回收消息
    void recycleUnchecked() {
        
        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) {//将要回收的Message对象添加到池中
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;//这里很明显是像链表采用头添加方式(如果不好理解可以this.next = spool)
                sPool = this;
                sPoolSize++;
            }
        }
    }
    
    
    public Handler getTarget() {
        return target;
    }
 
  
    






--------------------------------------主线程(AcitivtyThread中的mian)-------------------------
public static void main(String[] args){
    Process.setAgV0("<pre-initialized");
    Looper.prepareMainLooper();


    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    if(sMainThreadHandler==null)
       sMainThreadHandler = thread.getHandler();
    AsyncTask.init();
    Looper.loop();


    }
 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值