Android-0.Handler机制


Handler机制类似于Window下的跨线程Post消息处理机制, 依赖于消息循环,入队,出队。

Android为什么要设置只能通过Handler机制更新UI?
假设如果在一个Activity中,有多个线程去更新UI,并且都没有加锁机制,马么会产生生么样的问题?——更新界面混乱;
如果对更新UI 的操作都加锁处理的话会产生什么样子的问题?——性能下降
对于上述问题的考虑,Android提供了一套更新UI的机制,我们只需要遵循这样的机制就好了。
不用关心多线程的问题,更新UI的操作,都是在主线程的消息队列当中轮询处理的。

Handler机制

大致流程为:
Handler在子线程中发送消息,消息会被添加到MessageQueue消息队列中,再来由Handler所处的当前线程的Looper来不断的轮询MessageQueue以获取出队消息,最后调用dispatchMessage进行消息传递给handleMessage进行处理。

Android-0.Handler机制

基本使用方法

    private static final int MSG_UPDATE = 100 ;
    // 1.实例一个Handler对象(主线程)。
    Handler mHander = new Handler(){
        @Override
        public void handleMessage(Message msg) {//3.handleMessage中接收处理(子线程消息发送到主线程中处理)。
            if (MSG_UPDATE == msg.what){
                // todo.
            }
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {// 2.在子线程中使用Handler发送一个消息。
                Message Msg = new Message();
                Msg.what = MSG_UPDATE;
                mHander.sendMessage(Msg);
            }
        }).start();
    }

流程分析

1.实例一个Handler对象(主线程)。

    public Handler(Callback callback, boolean async) {
		......
        mLooper = Looper.myLooper();
       ......
        mQueue = mLooper.mQueue;
    }

Handler拥有mLooper和mQueue,从这里可以得出如下关系:

Handler中拥有LooperMessageQueueLooper中拥有MessageQueue,而且Handler中的MessageQueue来自于Looper中的MessageQueue

那么这个Looper是如何实例化的?
安卓应用程序作为一个控制类程序,都是有一个入口的,而这个入口就是ActivityThreadmain函数:
给Android Studio的onCreate设置一个断点,断下,堆栈如下:

Android-0.Handler机制
代码如下:
 public static void main(String[] args) {
		.....
        Looper.prepareMainLooper();
        .....
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");

以上的main函数代码中,我们看到两点:

1.我们之所以可以在Activity用Handler handler=new Handler()直接创建出来就默认绑定到主线程了,是因为上面的代码为我们做了绑定主线程的Looper的事情。

2.主线程的Looper是不能在程序中调用退出的,最后一句代码看到没,如果调用的话,就会抛出异常,退出主线程的循环是框架层在调用退出应用程序的时候才调用的。

    private static void prepare(boolean quitAllowed) {
    	  if (sThreadLocal.get() != null) {// 3.防止多次创建Looper
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));// 1.创建Looper,并设置到ThreadLocal中
    }
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
        	.....
            sMainLooper = myLooper();// 2.从ThreadLocal中取得创建的Looper
        }
    }
   public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

Handler与Looper是成对出现的,一个子线程发送消息,一个主线程接收消息,那么这边就涉及到了多线程,线程之间的通讯,是需要保证数据的安全,即数据隔离,所以使用到了ThreadLocal进行线程管理:即A线程只能取得A线程的数据,而不能取得B线程的数据。
同时prepare的代码也表明了一个线程只能关联一个Looper对象

2.在子线程中使用Handler发送一个消息。

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    ------------------------>
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
    	......
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
     ------------------------>
     public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
          	.....
            return false;
        }
        return 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);
    }

Handler的发送消息最终是通过它的mQueue成员变量的.enqueueMessage函数实现把消息添加到消息队列。

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            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");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            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;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                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;
    }

3.handleMessage中接收处理(子线程消息发送到主线程中处理)。

前面提到

Handler中拥有LooperMessageQueueLooper中拥有MessageQueue,而且Handler中的MessageQueue来自于Looper中的MessageQueue

以及ActivityThreadmain函数:

 public static void main(String[] args) {
		.....
        Looper.prepareMainLooper();
        .....
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");

Looper.loop()中不停的轮询:


    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        .....
        final MessageQueue queue = me.mQueue;
        boolean slowDeliveryDetected = false;

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            .......
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                msg.target.dispatchMessage(msg);
               ......
            } finally {
            }
			.......
            msg.recycleUnchecked();
        }
    }

内部调用了msg.target.dispatchMessage(msg)

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

转发到handleMessage