Handler機制的源碼分析

Handler,MessageQueue,Looper的關係

  • Looper的做用是在線程中處理消息的異步

  • MessageQueue用來存儲消息的隊列ide

  • Handler使用來定義具體處理消息的方式,以及發送消息;Android主線程中持有一個能夠更新UI的Handler;對其餘的線程,若是須要處理消息,能夠本身new一個Handler在線程的 run 方法中。oop

  • ThreadLocal:MessageQueue對象,和Looper對象在每一個線程中都只會有一個對象,怎麼能保證它只有一個對象,就經過ThreadLocal來保存。Thread Local是一個線程內部的數據存儲類,經過它能夠在指定線程中存儲數據,數據存儲之後,只有在指定線程中能夠獲取到存儲到數據,對於其餘線程來講則沒法獲取到數據。源碼分析

一.Looperui

源碼分析: Looper.prepare()方法;建立一個Looper的實例,可是該實例在一個線程中只能有一個;保存在ThreadLocal中,若是發現已經存在了Looper對象,會拋出一個異常。this

public static void prepare() {
        prepare(true);
    }
    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.loop()方法;loop()方法中有一個無限的循環。for(;;)那一段;線程執行到loop()方法以後會一直留在loop()方法中,直到被打斷終止 (源碼能夠看出,發送空消息就能夠打斷該循環,終止該線程)spa

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        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 (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            final long traceTag = me.mTraceTag;
            if (traceTag != 0) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            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();
        }
    }

二.Handler線程

重要的構造方法:code

  • 傳入某個線程thread的Looper對象;這樣這個Handler就是該thread的Handler了(和在該thread的run方法中直接new一個沒有參數的Handler的效果是同樣的;可是在外部定義可使咱們更好使用)
/**
    *  Use the provided {@link Looper} instead of the default one.
    *
    *  @param looper The looper, must not be null.
    */
   public Handler(Looper looper) {
       this(looper, null, false);
   }

   /**
    * Default constructor associates this handler with the {@link Looper} for the
    * current thread.
    *
    * If this thread does not have a looper, this handler won't be able to receive messages
    * so an exception is thrown.
    */
   public Handler() {
       this(null, false);
   }

三.MessageQueue對象

MessagerQueue是一個單向鏈表

HandlerThread

HandlerThread是Android系統本身實現的一個能夠實現 處理異步消息 的線程。簡單來講就是和UI線程是同樣的原理,經過Looper和Message通訊,讓該線程爲咱們服務。

具體能夠看源碼就能知道他的原理(咱們本身也能夠寫這樣的線程,可是系統給咱們的老是要好一點的)

@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

HandlerThread的使用

HandlerThread workThread = new HandlerThread();
workThread.start();
Handler handler = new Handler(workThread.getLooper());
相關文章
相關標籤/搜索