handler 源碼分析,handler源碼

來源:互聯網
上載者:User

handler 源碼分析,handler源碼

handler Looper 輪詢者MessageQueue 訊息對象1 主線程在一建立的時候就會調用,    public static void prepareMainLooper() {}構造方法。    public static void prepareMainLooper() {        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }2 在prepareMainLooper(){} 內部調用了 prepare(false);方法,這就是在子線程中new Handler()會抱錯的關鍵    prepare(quitAllowed) {}方法裡面設定了一個Looper對象,如果已經有了 Looper 對象,會拋出異常 Only one Looper may be created per thread    所以說一個 Handler只能有一個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));//建立一個 Looper構造器    }3 在 Looper 的構造器中    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);//建立了 MessageQueue對象        mRun = true;        mThread = Thread.currentThread();//線程對象    }4 但是在 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());            }        }        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;    }5 查看 Looper.myLooper();    public static Looper myLooper() {        return sThreadLocal.get();//返回的是一個 Looper對象,這裡就跟 2的結果一樣了    }所以在4 中拋出異常,跟2 也一樣了        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }所以敢肯定(1 2 3)的原理就是主線程 Handler的工作原理而 (4 5)就是我們手動建立 Handler的時候的工作原理。handler.sendMessage(msg);他做的是將訊息入隊操作6 經過源碼跟蹤,會發現在調用enqueueMessage(){}構造方法的時候,所做的事情就是將訊息就行,入棧處理   private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);//注意這裡,想必從字面意思理解,enqueueMessage就是入棧的意思吧    }7 看enqueueMessage()所做的事情    final boolean enqueueMessage(Message msg, long when) {        if (msg.isInUse()) {            throw new AndroidRuntimeException(msg + " This message is already in use.");        }        if (msg.target == null) {            throw new AndroidRuntimeException("Message must have a target.");        }        boolean needWake;        synchronized (this) {            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;            }            msg.when = when;            Message p = mMessages;            if (p == null || when == 0 || when < p.when) {                // New head, wake up the event queue if blocked.                msg.next = p;                mMessages = msg; //將訊息對象的引用賦值給 Message                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; //將訊息對象的引用賦值給 Message            }        }        if (needWake) {            nativeWake(mPtr);        }        return true;    }8 那麼問題來了,訊息引用都傳遞給Message對象了,那是如何從 Message中吧訊息分發出去,並響應呢?這就得看 Looper的源碼中的 public static void loop() {}方法其實 loop就是一個輪詢者,在不斷的從  MessageQueue中擷取訊息,可以看 loop()中的 Message msg = queue.next(); 內部實現源碼,next() 方法就是訊息佇列的出隊方法。不過由於這個方法的代碼稍微有點長,我就不貼出來了,它的簡單邏輯就是如果當前MessageQueue中存在mMessages(即待處理訊息),就將這個訊息出隊,然後讓下一條訊息成為mMessages,否則就進入一個阻塞狀態,一直等到有新的訊息入隊    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 (;;) {//天呐,在這裡居然是 for的空迴圈            //queue.next() 出現了,有興趣的可以點進去看看            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            Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }            msg.target.dispatchMessage(msg);//我們又發現了什嗎?對,msg.target代表的是Handler,調用了dispatchMessage方法            // 這樣我相信大家就都明白了為什麼handleMessage()方法中可以擷取到之前發送的訊息了吧!            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.recycle();        }    }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.