Handler总结

Posted by Lazy on July 3, 2016
  • 我们看下基本的概念
  • messagequeue===中文的翻译是消息队列,它的内部存储了一组消息,以队列的形式对外提供增加和删除的方法,但是他的内部不是队列的结构形式,而是采用单链表的数据结构来存储消息列表
  • looper==轮询器,也可以理解为消息循环,由于messagequeue是一个消息容器,所以他负责不断的去轮训消息,如果有消息处理的话就去处理消息,否则就一直等待着。他还有一个特殊的概念threadlocal ,并不是线程,他的作用是在每个线程中存储数据,负责绑定当前的线程的loop

  • 首先我们知道创建一个handel

	new Handler();就行了但是其中内部干了什么呢

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

                }

			//获取loper对象,如果lopper对象为空就会报异常,这就是为什么我们在子线程使用需要主动的调用 Looper.prepare();

            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;

        }

        

       我们看下Looper.prepare();的源码可以得知只有sThreadLocal为空的时候起创建了一个Looper对象

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

    }

    

    那么为什么我们在主线程就没有调用就没事呢

    其实你在创建activitythred的内部就给你调用了Looper.prepareMainLooper()调用了Looper.prepare()方法因此我们应用程序的主线程中会始终存在一个Looper对象从而不需要再手动去调用Looper.prepare()方法了

  • 然后我们发送消息需要什么?

      messag对message,我们看看怎么创建一个message,那么创建message有那些方式,2中,我们一般推荐使用  Message.obtain();为什么推荐这个我么你看下源码!
    
      //我们可以清楚,首先他会看Message对象是不是已经存在了,如果存在了就直接复用,没有直接创建,这样原因不说也明白了吧。
    
      `  public static Message obtain() {
    
      synchronized (sPoolSync) {
    
          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();
    

    }`

  • 有了消息我们就要发送出去,如何发送呢!

    `handler.sendMessage(message);`,这样我们就可以把消息发送出去。那么它里面是如何发送消息的,我们通过看源码得知他最终回调用sendMessageAtTime(),我们看下源码
    

	//其中msg参数就是我们发送的Message对象,而uptimeMillis参数则表示发送消息的时间,它的值等于自系统开机到当前时间的毫秒数再加上延迟时间

	 public boolean sendMessageAtTime(Message msg, long uptimeMillis) {

     	//如果quer为空就会停止轮训消息

        MessageQueue queue = mQueue;

        if (queue == null) {

            RuntimeException e = new RuntimeException(

                    this + " sendMessageAtTime() called with no mQueue");

            Log.w("Looper", e.getMessage(), e);

            return false;

        }

        //进入enqueueMessage

        return enqueueMessage(queue, msg, uptimeMillis);

    }

	//通过看源码我们知道,MessageQueue是在调用looper的时候创建的,因此一个Looper也就对应了一个MessageQueue。

    private Looper(boolean quitAllowed) {

        mQueue = new MessageQueue(quitAllowed);

        mThread = Thread.currentThread();

    }

    

    

    

    

    

    我们看下enqueueMessage的方法在这里进行消息的入队将消息插入到messagequene

        final boolean enqueueMessage(Message msg, long when) {

        if (msg.when != 0) {

            throw new AndroidRuntimeException(msg + " This message is already in use.");

        }

        //如果为空将报异常,msg.target就是handel

        if (msg.target == null && !mQuitAllowed) {

            throw new RuntimeException("Main thread not allowed to quit");

        }

        synchronized (this) {

        	//如果调用了quit就会赋值为true

            if (mQuiting) {

                RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");

                Log.w("MessageQueue", e.getMessage(), e);

                return false;

            } else if (msg.target == null) {

                mQuiting = true;

            }

            msg.when = when;

            Message p = mMessages;

            //在这里他们将按照时间的顺序排列

            if (p == null || when == 0 || when < p.when) {

                msg.next = p;

                mMessages = msg;

                this.notify();

            } else {

                Message prev = null;

                while (p != null && p.when <= when) {

                    prev = p;

                    p = p.next;

                }

                msg.next = prev.next;

                prev.next = msg;

                this.notify();

            }

        }

           if (needWake) {

           		//在native层进行消息的传递

                nativeWake(mPtr);

            }

        return true;

    }

  • 接下来我们看下消息的轮训 loop.loop()

	public static final void loop() {

    //获取Looper

    Looper me = myLooper();

    MessageQueue queue = me.mQueue;

    while (true) {

    	//这里面也是个死循环去取消息如果当前MessageQueue中存在mMessages(即待处理消息),就将这个消息出队,然后让下一条消息成为mMessages,否则就进入一个阻塞状态,一直等到有新的消息入队。
      //MessageQueue中的nex方法,去轮训消息内部是一个无限的循环轮询,这里面要想退出这个无限的循环只有queue.next()
      返回null而要让他返回null通过看源码mQuitting就行了也就是说只要调用quit就可以了
        Message msg = queue.next(); // might block

        if (msg != null) {

        //如果handel为空将直接退出循环

            if (msg.target == null) {

                return;

            }

            if (me.mLogging!= null) me.mLogging.println(

                    ">>>>> Dispatching to " + msg.target + " "

                    + msg.callback + ": " + msg.what

                    );

            //这里就会调用handeld的dispatchMessage进行消息的分发,为什么是msg.target是handel通过源码我们看到enqueueMessage里面进行的赋值 msg.target = this;我们看下怎么分发的

            msg.target.dispatchMessage(msg);

            if (me.mLogging!= null) me.mLogging.println(

                    "<<<<< Finished to    " + msg.target + " "

                    + msg.callback);

            msg.recycle();

        }

    }

}





//我们进入到这个方法

public void dispatchMessage(Message msg) {

    if (msg.callback != null) {
       //这个方法熟悉把就把消息传递到我们重写的主线程的方法了,在这里进行回调handleMessage
        handleCallback(msg);

    } else {

        if (mCallback != null) {

            if (mCallback.handleMessage(msg)) {

                return;

            }

        }



        handleMessage(msg);

    }

}