亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android Handler消息機(jī)制分析

 更新時(shí)間:2021年08月24日 11:14:26   作者:tandeneck  
這篇文章主要介紹了Android Handler消息機(jī)制分析,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

Handler是什么?

Handler 是一個(gè)可以實(shí)現(xiàn)多線程間切換的類(lèi),通過(guò) Handler 可以輕松地將一個(gè)任務(wù)切換到 Handler 所在的線程中去執(zhí)行。我們最常用的使用的場(chǎng)景就是更新 UI 了,比如我們?cè)谧泳€程中訪問(wèn)網(wǎng)絡(luò),拿到數(shù)據(jù)后我們 UI 要做一些改變,如果此時(shí)我們直接訪問(wèn) UI 控件,就會(huì)觸發(fā)異常了。這個(gè)時(shí)候我們往往會(huì)通過(guò) Handler 將更新 UI 的操作切換到主線程中。

Handler 的基本使用

用法一:通過(guò) send 方法

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private MyHandler mMyHandler = new MyHandler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = Message.obtain(mMyHandler,0,"通過(guò) send 方法");
                mMyHandler.sendMessage(message);
            }
        }).start();
    }

    private static class MyHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 0:
                    Toast.makeText(MainActivity.this,msg.obj.toString(),Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }
}

用法二:通過(guò) post 方法

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private Handler mMyHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                mMyHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this,"通過(guò)post方法",Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }).start();
    }
}

其實(shí),通過(guò) post 方法最后通過(guò) send 方法來(lái)完成的。這個(gè)我們稍后會(huì)分析。講到 Handler,我們不得不提起 MessageQueue 類(lèi) 和 Looper 類(lèi)。 Handler 通過(guò) send 方法 發(fā)送一個(gè)消息,會(huì)調(diào)用 MessageQueue 的 enqueueMessage 方法 將這個(gè)消息插入到 MessageQueue 中,然后 Looper 發(fā)現(xiàn)有消息來(lái)臨時(shí),通過(guò)一系列的方法調(diào)用后,Handler 如果是通過(guò) post 方法就會(huì)執(zhí)行 post 方法里面的 Runnable ,如果是通過(guò) send 方法就會(huì)執(zhí)行 Handler 的 handleMessage 。這么說(shuō)感覺(jué)有點(diǎn)云里霧里的,讓我們仔細(xì)的來(lái)看下 Handler 類(lèi)、MessageQueue 類(lèi)和 Looper 類(lèi)。

Handler 類(lèi)

我們先來(lái)看下 Handler 類(lèi)的結(jié)構(gòu)


Handler 類(lèi)結(jié)構(gòu).png

Handler 的工作主要包括消息的發(fā)送和接收過(guò)程。一般來(lái)說(shuō),消息的發(fā)送和消息的接收是位于不同的線程。我們首先來(lái)看 post 方法。

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is 
 * attached. 
 *  
 * @param r The Runnable that will be executed.
 * 
 * @return Returns true if the Runnable was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

這里調(diào)用了 sendMessageDelayed 方法

/**
 * Enqueue a message into the message queue after all pending messages
 * before (current time + delayMillis). You will receive it in
 * {@link #handleMessage}, in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

而 sendMessageDelayed 又調(diào)用了 sendMessageAtTime() 方法

/**
 * Enqueue a message into the message queue after all pending messages
 * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
 * Time spent in deep sleep will add an additional delay to execution.
 * You will receive it in {@link #handleMessage}, in the thread attached
 * to this handler.
 * 
 * @param uptimeMillis The absolute time at which the message should be
 *         delivered, using the
 *         {@link android.os.SystemClock#uptimeMillis} time-base.
 *         
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    return enqueueMessage(queue, msg, uptimeMillis);
}

千呼萬(wàn)喚始出來(lái),在 sendMessageAtTime 這個(gè)方法我們終于看到了 MessageQueue 類(lèi),這里的邏輯主要向 MessageQueue 中插入了一條消息(Message)。咦?我們不是通過(guò) post 方法傳進(jìn)來(lái)的 Runnable 么?什么時(shí)候變成 Message 了?其實(shí)剛才我們忽略了一個(gè)方法。

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

沒(méi)錯(cuò),就是 getPostMessage 方法

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

從這里看到,系統(tǒng)通過(guò)調(diào)用 Message.obtain() 創(chuàng)建一個(gè) Message,并把我們通過(guò) post 方法傳進(jìn)來(lái)的 Runnable 賦值給 Message 的 callback。這里的 callback 需要留意,這個(gè)在我們之后的分析會(huì)用到。接下里我們看 Handler 的 send 方法。

/**
 * Pushes a message onto the end of the message queue after all pending messages
 * before the current time. It will be received in {@link #handleMessage},
 * in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

是不是很熟悉?post 方法也是調(diào)用這個(gè) sendMessageDelayed 方法,這也是為什么我們之前說(shuō) post 方法 也是通過(guò) send 方法來(lái)執(zhí)行的。到此為止,我們已經(jīng)弄懂 Handler 的消息發(fā)送過(guò)程??偨Y(jié)的來(lái)說(shuō),通過(guò) post 方法系統(tǒng)會(huì)把 我們傳進(jìn)來(lái)的 Runnable 轉(zhuǎn)變成 Message,然后就和 send 方法一樣,通過(guò)一系列的方法調(diào)用之后把 Message 插入到 MessageQueue 當(dāng)中。至于 Handler 的消息接收過(guò)程,我們暫且放一下,先來(lái)看 MessageQueue 類(lèi)。

MessageQueue 類(lèi)

前面說(shuō)到,Handler 發(fā)送消息的過(guò)程就是往 MessageQueue 中插入 一個(gè) Message,即調(diào)用 MessageQueue 的 enqueueMessage 方法。首先,我們來(lái)看下 MessageQueue 的類(lèi)結(jié)構(gòu)


MessageQueue類(lèi)結(jié)構(gòu).png

我們看到 MessageQueue 是比較簡(jiǎn)單的。其實(shí),MessageQueue 主要包含兩個(gè)操作:插入和讀取。

插入方法: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("MessageQueue", 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;
}

讀取方法:next

需要注意的是:讀取操作本身會(huì)伴隨著刪除操作

Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                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;
                    if (false) Log.v("MessageQueue", "Returning message: " + msg);
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf("MessageQueue", "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

Looper 類(lèi)

首先,我們也來(lái)看下 Looper 的類(lèi)結(jié)構(gòu)


Looper類(lèi)結(jié)構(gòu).png

關(guān)于 Looper ,我們首先要明確一點(diǎn),Looper 是線程相關(guān)的,即每個(gè)線程的 Looper 是不一樣的,但是線程默認(rèn)是沒(méi)有 Looper 的??赡軙?huì)有點(diǎn)繞,要理清這里面的邏輯的關(guān)系,我們首先要了解 ThreadLocal,關(guān)于 ThreadLocal 網(wǎng)上的資料挺多的。簡(jiǎn)單地來(lái)說(shuō),ThreadLocal 是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類(lèi),比如有有一個(gè) int 類(lèi)型的 x,在線程 A 的值是 1,在線程 B 的值可以是 0,1,2,..,在線程 C 的值可以是 0,1,2... 我們來(lái)看下 Looper 相關(guān)的源碼

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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));
}

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static Looper myLooper() {
    return sThreadLocal.get();
}

我們?yōu)槭裁匆鞔_ Looper 是線程相關(guān)的呢?因?yàn)?Handler 創(chuàng)建的時(shí)候會(huì)采用當(dāng)前線程的 Looper 來(lái)構(gòu)造消息循環(huán)系統(tǒng)的。Handler 創(chuàng)建的時(shí)候要先創(chuàng)建 Looper,這時(shí)候疑問(wèn)就來(lái)了?我們平常創(chuàng)建 Handler 的時(shí)候直接就創(chuàng)建了啊,沒(méi)有創(chuàng)建什么 Looper 啊。這是因?yàn)槲覀兺ǔJ窃谥骶€程 ActivityThread 中創(chuàng)建 Handler。我們看到 Loop 類(lèi)中有個(gè) prepareMainLooper 方法。

/**
 * Initialize the current thread as a looper, marking it as an
 * application's main looper. The main looper for your application
 * is created by the Android environment, so you should never need
 * to call this function yourself.  See also: {@link #prepare()}
 */
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

主線程在創(chuàng)建時(shí),就會(huì)調(diào)用這個(gè)方法創(chuàng)建 Looper。但是如果我們?cè)谧泳€程(如下代碼)直接創(chuàng)建 Handler 就會(huì)拋出異常

        new Thread(new Runnable() {
            @Override
            public void run() {
                //Looper.prepare();
                Handler handler = new Handler();
               // Looper.loop();
            }
        }).start();

這時(shí)只要我們把注釋去掉就不會(huì)報(bào)異常了。通過(guò)源碼我們知道 Looper.prepare() 主要是為當(dāng)前線程一個(gè) Looper 對(duì)象。

 /** Initialize the current thread as a looper.
  * This gives you a chance to create handlers that then reference
  * this looper, before actually starting the loop. Be sure to call
  * {@link #loop()} after calling this method, and end it by calling
  * {@link #quit()}.
  */
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()方法是干什么的呢?其實(shí),Looper 最重要的一個(gè)方法就是 loop 方法了。只有調(diào)用 loop 后,消息系統(tǒng)才會(huì)真正地起作用。我們來(lái)看 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();
    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
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        msg.target.dispatchMessage(msg);

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

我們可以看到 loop 方法是一個(gè)死循環(huán),在這個(gè)死循環(huán)方法里面會(huì)調(diào)用 MessageQueue 的 next 方法來(lái)獲取新消息。但是如果 next 方法返回了 null,loop 就退出循環(huán)。這種情況發(fā)生在 Loop 的 quit 方法被調(diào)用時(shí),Looper 會(huì) 調(diào)用 MessageQueue 的 quit 方法來(lái)通知消息隊(duì)列退出,當(dāng)消息隊(duì)列被標(biāo)記退出狀態(tài)時(shí),它的 next 方法就會(huì)返回 null。由于 next 是一個(gè)阻塞方法,所以 loop 也會(huì)一直阻塞在那里,如果有消息到來(lái), msg.target.dispatchMessage(msg)。這個(gè) msg.target 就是發(fā)送這個(gè)消息的 Handler 對(duì)象啦。這樣 Handler 發(fā)送的消息最終又交給自己的 dispatchMessage 方法來(lái)處理了。因?yàn)?Handler 的 dispatchMessage 方法是創(chuàng)建 Handler 時(shí)使用的 Looper 中執(zhí)行的,這樣就成功地完成線程切換了。

Handler 的消息接收過(guò)程

經(jīng)過(guò)跋山涉水,通過(guò) Handler 發(fā)送的消息最終又會(huì)回到自己的 diapatchMessage 中來(lái),那就讓我們來(lái)看下 diapatchMessage 方法。

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

首先,檢查 Messgae 的 callback 是否為 null,不為 null 就調(diào)用 handleCallback 方法,這個(gè) Message 的 callback 就是我們之前post的。其次,檢查 mCallback 是否為 null ,不為 null 就調(diào)用 mCallback 的 handleMessage 方法來(lái)處理消息。如果我們是通過(guò)繼承 Handler 來(lái)實(shí)現(xiàn)邏輯的話,此時(shí)的mCallback 是為空的,即會(huì)調(diào)用 handleMessage(msg),也就是我們重寫(xiě)的 handleMessage 方法。至此,完成了完美的閉環(huán)。

有的同學(xué)可能會(huì)疑問(wèn) mCallback 是什么?什么時(shí)候會(huì)為空?

 /**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
public interface Callback {
    public boolean handleMessage(Message msg);
}

 /**
 * Constructor associates this handler with the {@link Looper} for the
 * current thread and takes a callback interface in which you can handle
 * messages.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 *
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Callback callback) {
    this(callback, false);
}

通過(guò)源碼可以看出,我們也可以采用 Handler handler = new Handler(callback) 來(lái)創(chuàng)建 Handler,這時(shí)dispatchMessage 里面就會(huì)走 mCallback 不為空的邏輯。

到此這篇關(guān)于Android Handler消息機(jī)制分析的文章就介紹到這了,更多相關(guān)Android Handler消息機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論