Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android異步消息機制,Handler,Looper,MessageQueue的關系

android異步消息機制,Handler,Looper,MessageQueue的關系

編輯:關於Android編程

前言:

(1)在android中線程間的消息通信是通過handler實現的。handler的常見應用:因為在android中對UI操作只能在主線程中操作,而一些耗時的操作又不能在主線程進行,所以會在子線程做一些網絡請求等的耗時操作,然後通過handler把子線程的任務切換到主線程中,在主線程中進行UI操作。如下代碼:

 private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            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() {
                Message message = Message.obtain();
                message.what = 1;
                handler.sendMessage(message);
            }
        }).start();

    }

 

(2)handler的運行其實需要looper和messageQueue支持,只是當新建Activity已經幫我們新建了looper和messageQueue。如果在子線程使用handler,必須調用Looper.prepare和Looper.loop。如下代碼:

 

    class MyThread implements Runnable{

        private Handler handler;

        @Override
        public void run() {
            Looper.prepare();
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                }
            };
            Looper.loop();
        }
    }

(3)handler的應用流程。首先通過Looper.prepare(),將Looper綁定到當前線程,創建Looper實例時會創建一個MessageQueue。當新建一個Handler實例時會獲取到當前的線程的Looper和MessageQUeue。當通過handler.sendMessage(message)方法時會把Message插入到MessageQueue中。最後通過Looper.loop()不停遍歷MessageQueue,得到Message,並交給msg.target處理,target就是當前handler(handle賦值給msg.target是在handler.sendMessage(message)中實現的)。target會調用msg.target.dispatchMessage(msg)處理,dispatchMessage最後會調用 handleMessage(msg)處理message。handleMessage也是我們需要重寫的方法。下面將下各方法的實現原理。

 

1.Looper.prepare()

 

Looper.prepare()的作用是創建一個Looper並綁定到當前線程,同時創建一個MessageQueue。Looper綁定到當前線程通過ThreadLocal實現的。

ThreadLocal的作用:為不同線程互不干擾的存儲和提供數據(具體原理可以看下singwhatiwanna大神的這篇文章點擊打開鏈接)。

在代碼的78行sThreadLocal.set(new Looper(quitAllowed)),新建了一個Looper實例存儲到了ThreadLocal中,並在這之前判定了ThreadLocal之前是否存儲了Looper,不為null則拋出異常,這樣保證了一個線程只有一個Looper。

 

 

51 
52 public final class More ...Looper {
53     private static final String TAG = "Looper";
54 
55     // sThreadLocal.get() will return null unless you've called prepare().
56     static final ThreadLocal sThreadLocal = new ThreadLocal();
57     private static Looper sMainLooper;  // guarded by Looper.class
58 
59     final MessageQueue mQueue;
60     final Thread mThread;
61 
62     private Printer mLogging;


70     public static void More ...prepare() {
71         prepare(true);
72     }
73 
74     private static void More ...prepare(boolean quitAllowed) {
75         if (sThreadLocal.get() != null) {
76             throw new RuntimeException("Only one Looper may be created per thread");
77         }
78         sThreadLocal.set(new Looper(quitAllowed));
79     }

下面看下Looper的構造方法。在新建Looper會創建一個MessageQueue。一個就實現了一個線程只有一個Looper和MessageQueue。

 

 

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

2.新建一個Handler對象。

Handler的構造方法的第198行mLooper = Looper.myLooper()獲取了當前線程的Looper。再看下Looper.myLooper()的實現,其實是獲取了LocalThread存儲的Looper, return sThreadLocal.get()第161行,就是在代碼78行保存的Looper。
mQueue = mLooper.mQueue(203行)獲取了MessageQueu。這樣通過新建一個Handler對象,通過ThreadLocal使Handler和Looper,MessageQueue聯系到一起。

 

187
188    public More ...Handler(Callback callback, boolean async) {
189        if (FIND_POTENTIAL_LEAKS) {
190            final Class klass = getClass();
191            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
192                    (klass.getModifiers() & Modifier.STATIC) == 0) {
193                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
194                    klass.getCanonicalName());
195            }
196        }
197
198        mLooper = Looper.myLooper();
199        if (mLooper == null) {
200            throw new RuntimeException(
201                "Can't create handler inside thread that has not called Looper.prepare()");
202        }
203        mQueue = mLooper.mQueue;
204        mCallback = callback;
205        mAsynchronous = async;
206    }

myLooper方法,通過sThreadLocal.get()獲取了保存在ThreadLocal當前線程的Looper.

160    public static Looper More ...myLooper() {
161        return sThreadLocal.get();
162    }

3.handler.sendMessage(message)
先看下代碼。不管是sendMessage還是sendEmptyMessage最後都是調用enqueueMessage(626行開始).我們看下enqueueMessage方法實現。queue.enqueueMessage(msg, uptimeMillis)(631行)把message加入到了MessageQueue中。msg.target = this(627行),把當前Handler賦值給了msg.taget。當Looper遍歷MessageQueue,取出Message會交給msg.taget處理,也就是交給handler處理了。



505 public final boolean More ...sendMessage(Message msg)
506    {
507        return sendMessageDelayed(msg, 0);
508    }



516
517    public final boolean More ...sendEmptyMessage(int what)
518    {
519        return sendEmptyMessageDelayed(what, 0);
520    }


531    public final boolean More ...sendEmptyMessageDelayed(int what, long delayMillis) {
532        Message msg = Message.obtain();
533        msg.what = what;
534        return sendMessageDelayed(msg, delayMillis);
535    }



592    public boolean More ...sendMessageAtTime(Message msg, long uptimeMillis) {
593        MessageQueue queue = mQueue;
594        if (queue == null) {
595            RuntimeException e = new RuntimeException(
596                    this + " sendMessageAtTime() called with no mQueue");
597            Log.w("Looper", e.getMessage(), e);
598            return false;
599        }
600        return enqueueMessage(queue, msg, uptimeMillis);
601    }



626    private boolean More ...enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
627        msg.target = this;
628        if (mAsynchronous) {
629            msg.setAsynchronous(true);
630        }
631        return queue.enqueueMessage(msg, uptimeMillis);
632    }

 

 

 

4.Looper.loop().

當MessageQueue有消息時,會遍歷MessageQueue,獲取到Message,然後交給Handler處理。MessageQueue沒有消息時則處於阻塞狀態。

 

  public static void More ...loop() {
110        final Looper me = myLooper();
111        if (me == null) {
112            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
113        }
114        final MessageQueue queue = me.mQueue;
115
116        // Make sure the identity of this thread is that of the local process,
117        // and keep track of what that identity token actually is.
118        Binder.clearCallingIdentity();
119        final long ident = Binder.clearCallingIdentity();
120
121        for (;;) {
122            Message msg = queue.next(); // might block
123            if (msg == null) {
124                // No message indicates that the message queue is quitting.
125                return;
126            }
127
128            // This must be in a local variable, in case a UI event sets the logger
129            Printer logging = me.mLogging;
130            if (logging != null) {
131                logging.println(">>>>> Dispatching to " + msg.target + " " +
132                        msg.callback + ": " + msg.what);
133            }
134
135            msg.target.dispatchMessage(msg);
136
137            if (logging != null) {
138                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
139            }
140
141            // Make sure that during the course of dispatching the
142            // identity of the thread wasn't corrupted.
143            final long newIdent = Binder.clearCallingIdentity();
144            if (ident != newIdent) {
145                Log.wtf(TAG, "Thread identity changed from 0x"
146                        + Long.toHexString(ident) + " to 0x"
147                        + Long.toHexString(newIdent) + " while dispatching to "
148                        + msg.target.getClass().getName() + " "
149                        + msg.callback + " what=" + msg.what);
150            }
151
152            msg.recycleUnchecked();
153        }
154    }

在代碼110到114行獲取了Looper和MessageQueue,如果Looper為空則會拋出異常。

代碼121到153無限便利MessageQueue.

代碼122行(Message msg = queue.next();)獲取到了Message,如果沒有則處於阻塞狀態。

代碼135行(msg.target.dispatchMessage(msg);)msg交給了msg.target處理,target就是在新建Handler實例時賦值給它的當前Handler。這裡把msg交給了handler.dispatchMessage(msg)處理,我們看下dispatchMessage的代碼。


93     public void More ...dispatchMessage(Message msg) {
94         if (msg.callback != null) {
95             handleCallback(msg);
96         } else {
97             if (mCallback != null) {
98                 if (mCallback.handleMessage(msg)) {
99                     return;
100                }
101            }
102            handleMessage(msg);
103        }
104    }


在dispatchMessage方法中如果msg.callback和mCallback為null則交給102行(handleMessage(msg);)處理,handlerMessage就是我們需要重寫,去處理返回的消息。
如果msg.callback不為null,看下95行handleCallback(msg),該方法實現739行(message.callback.run()),其實callback就是一個Runnable。我們在handler.post(runnable)設置了callback。

 


     private static void More ...handleCallback(Message message) {
739        message.callback.run();
740    }
741

我們看下post方法。其實在post方法中也是調用了sendMessageDelayed(326行),這個和sendMessage,sendEmptyMessage最後調用的方法是一樣的。sendMessageDelayed方法的第一個參數類型是Message.我們看下getPostMessage方法。它的實現其實就是創建了一個空的Message,給Message.callback賦值了Runnable,727行(m.callback = r),而 m.callback就是在dispatchMessage方法中最後消息交給其處理(95行)。所以handler.post(runnable)實現了消息的發送(sendMessage),消息傳遞過來後的處理(handleMessage(msg);)。發送Message時,只是攜帶了Runnable的一個空的Message,最後在message.callback.run()(739行)處理消息。所以我們要重寫run方法處理消息。

324    public final boolean More ...post(Runnable r)
325    {
326       return  sendMessageDelayed(getPostMessage(r), 0);
327    }


 
725    private static Message More ...getPostMessage(Runnable r) {
726        Message m = Message.obtain();
727        m.callback = r;
728        return m;
729    }
730

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved