Android技術21:Android非同步訊息處理線程,android非同步
Android非同步訊息處理線程,該線程一直處於無限迴圈之中,每次從Message Queue中讀取訊息,然後回調訊息處理的方法,Handler的HandlerMessage中處理訊息。如果訊息佇列為空白,該線程就掛,等待訊息佇列中有訊息進來,就喚醒線程。
1.Android非同步線程內部結構
線上程內部有一個或者多個Handler對象,外部程式通過Handler對象向線程發送非同步訊息,訊息經過Handler傳遞到Message Queue對象中,每個線程內部只包含一個一個訊息佇列對象,線程主執行函數從訊息佇列中讀取訊息,並回調Handler對象方法handlerMessage()。
2.Thread Local Storage
程式員通過Looper類的靜態方法prepare()為線程建立訊息佇列對象。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
1 private static void prepare(boolean quitAllowed) {2 if (sThreadLocal.get() != null) {3 throw new RuntimeException("Only one Looper may be created per thread");4 }5 sThreadLocal.set(new Looper(quitAllowed));6 }
線程局部對象TLS,該對象是通過sThreadLocal的set方法設定進去。
3.Looper
Looper對象作用:一是建立訊息佇列,二是讓當前線程提供靜態方法loop()進入迴圈,並從訊息佇列中讀取訊息。
1 private Looper(boolean quitAllowed) {2 mQueue = new MessageQueue(quitAllowed);3 mRun = true;4 mThread = Thread.currentThread();5 }
當需要把一個線程變為非同步訊息處理線程時,應該在Thread類的run()函數中先調用Looper.prepare()為線程建立一個訊息佇列對象Message Queue.然後調用Looper.loop()使當前線程進入訊息處理迴圈。
1 public static void loop() { 2 final Looper me = myLooper(); 3 if (me == null) { 4 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 5 } 6 final MessageQueue queue = me.mQueue; 7 8 // Make sure the identity of this thread is that of the local process, 9 // and keep track of what that identity token actually is.10 Binder.clearCallingIdentity();11 final long ident = Binder.clearCallingIdentity();12 13 for (;;) {14 Message msg = queue.next(); // might block15 if (msg == null) {16 // No message indicates that the message queue is quitting.17 return;18 }19 20 // This must be in a local variable, in case a UI event sets the logger21 Printer logging = me.mLogging;22 if (logging != null) {23 logging.println(">>>>> Dispatching to " + msg.target + " " +24 msg.callback + ": " + msg.what);25 }26 27 msg.target.dispatchMessage(msg);28 29 if (logging != null) {30 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);31 }32 33 // Make sure that during the course of dispatching the34 // identity of the thread wasn't corrupted.35 final long newIdent = Binder.clearCallingIdentity();36 if (ident != newIdent) {37 Log.wtf(TAG, "Thread identity changed from 0x"38 + Long.toHexString(ident) + " to 0x"39 + Long.toHexString(newIdent) + " while dispatching to "40 + msg.target.getClass().getName() + " "41 + msg.callback + " what=" + msg.what);42 }43 44 msg.recycle();45 }
4.Message Queue
從上面看出通過queue.next(),讀取一條訊息,但是在Framework中並沒有訊息佇列對象,Message Queue兩個主要函數讀取訊息和添加訊息,分別為next(),enquenceMessage().但是真正實現並不是在Framework層而是通過JNI在C代碼中實現。
1 private native static int nativeInit();2 private native static void nativeDestroy(int ptr);3 private native static void nativePollOnce(int ptr, int timeoutMillis);4 private native static void nativeWake(int ptr);
5.Handler
在構造Handler對象前,必須經過執行過Looper.prepare(),在Looper.loop()函數中,不同的Message對應不同的Handler對象,從而回調不同的handlerMessage()函數。
java或者android實現非同步方式只可以用多線程,有沒有其他的方式
android中有AsyncQueryHandler和AsyncTask都是用來非同步訊息傳遞的,不過本質都是多線程,不過Android幫你封裝好了方便調用而已。希望能夠協助到你!
對於Android擷取線程執行完後的結果的問題
其實Google早就意識到這個問題。Message裡有一個send的方法。如下
Message msg = mhandler.obtainMessage(MSG_UPDATE, imgIndex, 0);
mhandler.sendMessage(msg);
然後重寫handler的 handlerMessage方法,如下:
private Handler mhandler = new Handler(){
@Override
public void handleMessage(Message msg){
if(msg.what == MSG_UPDATE){
//你要的操作...
}
}
};
基本上就是這樣啦!