android的handler、looper、Message之間的關系


handler:綁定到一個線程上,一個線程可以有多個handler

looper:線程跟looper是一一對應的,所以looper不能被調用兩次否則會拋出異常

messge:handler利用message來攜帶消息

messagQueue:用來狀態message,一個looper對應一個消息隊列

如何來判斷一個消息隊列對應一個handler呢,在sendmessage中獲取到一個消息隊列的持有者looper

looper的兩個方法:prepare()和loop()

1.

public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(true));
}

給當前線程一個設定一個looper實例

2.

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mRun = true;
        mThread = Thread.currentThread();
}

給這個looper創建一個消息隊列(在構造函數中),並返回當前的線程

3.

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.recycle();
        }
}
 public static Looper myLooper() {
        return sThreadLocal.get();
    }

直接拿到該looper實例中的消息隊列,然后循環每一個message(進入了無限循環),遍歷消息之后會通過這個message的handler進行分發。

msg.target.dispatchMessage(msg); 中的target是handler

總結looper的主要作用

1) 與當前線程綁定,保證一個線程只會有一個Looper實例,同時一個Looper實例也只有一個MessageQueue。
2) loop()方法,不斷從MessageQueue中去取消息,交給消息的target屬性的dispatchMessage去處理。

handler

public Handler() {
        this(null, false);
}
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;
    }

handler綁定到looper上,由於一個looper對一個一個消息隊列,這樣這個handler就綁定到這個looper上了,也同時綁定到了這個線程上。

handler.sendMessgae()是用來講Message添加進消息隊列的。。dispatchmessage才是用於分發的(如上looper介紹)

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

handleMessage此時是空的函數,需要我們之后的復寫

步驟:

1、首先Looper.prepare()在本線程中保存一個Looper實例,然后該實例中保存一個MessageQueue對象;因為Looper.prepare()在一個線程中只能調用一次,所以MessageQueue在一個線程中只會存在一個。

2、Looper.loop()會讓當前線程進入一個無限循環,不端從MessageQueue的實例中讀取消息,然后回調msg.target.dispatchMessage(msg)方法。

3、Handler的構造方法,會首先得到當前線程中保存的Looper實例,進而與Looper實例中的MessageQueue想關聯。

4、Handler的sendMessage方法,會給msg的target賦值為handler自身,然后加入MessageQueue中。

5、在構造Handler實例時,我們會重寫handleMessage方法,也就是msg.target.dispatchMessage(msg)最終調用的方法。

6、handler也可以進行存在於子線程中,為什么我們一般見到的都在主線程中呢?因為一般是針對UI空間更新的操作是不安全的所以handler放在主線程中,如果不存在這樣的業務,當然可以用handler

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM