Looper 和Handler 是理解好AsyncTask的一個基礎,我們可以先從這裡開始,先給出一個主執行緒和子執行緒互相通訊的例子。
1 package com.example.loopertest; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Handler; 6 import android.os.Looper; 7 import android.os.Message; 8 import android.util.Log; 9 10 public class MainActivity extends Activity { 11 12 public static final int SIGNAL_1 = 0x1; 13 public static final int SIGNAL_2 = 0x2; 14 15 public static int flagValue = 0; 16 private LooperThread thread; 17 private Handler uiHandler = new Handler() { 18 @Override 19 public void handleMessage(Message msg) { 20 // TODO Auto-generated method stub 21 switch (msg.what) { 22 case SIGNAL_1: 23 Log.v("MainActivity", "主執行緒收到子執行緒發來的訊息"); 24 flagValue++; 25 if (flagValue == 5) { 26 Log.v("MainActivity", "now flagvalue is over 5"); 27 Log.v("MainActivity", 28 "quit 前 thread.isAlive?" + thread.isAlive()); 29 thread.cHandler.getLooper().quit(); 30 Log.v("MainActivity", 31 "quit 後 thread.isAlive?" + thread.isAlive()); 32 } else { 33 Log.v("MainActivity", "thread.isAlive?" + thread.isAlive()); 34 thread.cHandler.sendEmptyMessageDelayed(SIGNAL_1, 3000); 35 } 36 break; 37 case SIGNAL_2: 38 thread.cHandler.sendEmptyMessage(SIGNAL_1); 39 break; 40 default: 41 break; 42 } 43 } 44 }; 45 46 @Override 47 protected void onCreate(Bundle savedInstanceState) { 48 super.onCreate(savedInstanceState); 49 setContentView(R.layout.activity_main); 50 51 thread = new LooperThread(); 52 thread.start(); 53 uiHandler.sendEmptyMessage(SIGNAL_2); 54 55 new Thread() { 56 public void run() { 57 while (true) { 58 try { 59 Thread.sleep(10000); 60 } catch (InterruptedException e) { 61 // TODO Auto-generated catch block 62 e.printStackTrace(); 63 } 64 Log.v("MainActivity", 65 "第三個子執行緒裡面每隔10s判斷 thread.isAlive?" 66 + thread.isAlive()); 67 } 68 } 69 }.start(); 70 71 } 72 73 class LooperThread extends Thread { 74 public Handler cHandler; 75 76 @Override 77 public void run() { 78 79 // 例項化messagequeue 80 Looper.prepare(); 81 82 cHandler = new Handler() { 83 @Override 84 public void handleMessage(Message msg) { 85 // TODO Auto-generated method stub 86 switch (msg.what) { 87 case SIGNAL_1: 88 Log.v("MainActivity", "子執行緒收到主執行緒發來的訊息"); 89 uiHandler.sendEmptyMessageDelayed(SIGNAL_1, 3000); 90 break; 91 default: 92 break; 93 } 94 } 95 }; 96 Log.v("MainActivity", "loop以前的語句"); 97 Looper.loop(); 98 99 Log.v("MainActivity", "loop以後的語句"); 100 101 } 102 103 } 104 105 }
看一下執行結果
04-30 07:17:58.754: V/MainActivity(597): loop以前的語句 04-30 07:17:58.784: V/MainActivity(597): 子執行緒收到主執行緒發來的訊息 04-30 07:18:01.794: V/MainActivity(597): 主執行緒收到子執行緒發來的訊息 04-30 07:18:01.794: V/MainActivity(597): thread.isAlive?true 04-30 07:18:04.804: V/MainActivity(597): 子執行緒收到主執行緒發來的訊息 04-30 07:18:07.814: V/MainActivity(597): 主執行緒收到子執行緒發來的訊息 04-30 07:18:07.814: V/MainActivity(597): thread.isAlive?true 04-30 07:18:08.780: V/MainActivity(597): 第三個子執行緒裡面每隔10s判斷 thread.isAlive?true 04-30 07:18:10.824: V/MainActivity(597): 子執行緒收到主執行緒發來的訊息 04-30 07:18:13.834: V/MainActivity(597): 主執行緒收到子執行緒發來的訊息 04-30 07:18:13.834: V/MainActivity(597): thread.isAlive?true 04-30 07:18:16.844: V/MainActivity(597): 子執行緒收到主執行緒發來的訊息 04-30 07:18:18.782: V/MainActivity(597): 第三個子執行緒裡面每隔10s判斷 thread.isAlive?true 04-30 07:18:19.844: V/MainActivity(597): 主執行緒收到子執行緒發來的訊息 04-30 07:18:19.844: V/MainActivity(597): thread.isAlive?true 04-30 07:18:22.854: V/MainActivity(597): 子執行緒收到主執行緒發來的訊息 04-30 07:18:25.864: V/MainActivity(597): 主執行緒收到子執行緒發來的訊息 04-30 07:18:25.864: V/MainActivity(597): now flagvalue is over 5 04-30 07:18:25.864: V/MainActivity(597): quit 前 thread.isAlive?true 04-30 07:18:25.874: V/MainActivity(597): loop以後的語句 04-30 07:18:25.874: V/MainActivity(597): quit 後 thread.isAlive?false 04-30 07:18:28.785: V/MainActivity(597): 第三個子執行緒裡面每隔10s判斷 thread.isAlive?false
這個例子就是用來 在android裡面 主執行緒和子執行緒進行通訊的,大家可以看一下程式碼,另外還有第三個執行緒在不斷偵測 子執行緒如何結束。
實際上就是子執行緒和主執行緒每隔3s 通訊一次,然後通訊的時候那個引數值 就每次加1,一直加到5的時候 子執行緒就結束了。
例子裡面也可以看出來 looper的訊息佇列在沒有quit的時候 子執行緒是會一直執行的,也就是誰looper.loop()後面的程式碼是不會執行的,
只有當quit以後 loop()的程式碼才會執行,這點大家要注意了。
然後我們可以藉著這個清晰得例子,來理一下 looper和handler之間是如何通訊的。
首先我們呼叫的是Looper.prepare(); 這句話,我們來看一下原始碼是怎麼寫的,
1 public static void prepare() { 2 if (sThreadLocal.get() != null) { 3 throw new RuntimeException("Only one Looper may be created per thread"); 4 } 5 sThreadLocal.set(new Looper()); 6 }
一下就能看出來 如果get()的值不是空 那麼就要丟擲這個異常,這樣就能解釋我們一個執行緒 肯定只能有一個looper了,並且Looper.prepare() 在一個執行緒裡面只能呼叫一次,否則也要拋異常。
當然了 我們可以點到這個set方法裡面看一下 大概做了什麼操作。
1 // sThreadLocal.get() will return null unless you've called prepare(). 2 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
然後我們進入threadlocal這個類裡面的set方法看看。
1 /** 2 * Sets the value of this variable for the current thread. If set to 3 * {@code null}, the value will be set to null and the underlying entry will 4 * still be present. 5 * 6 * @param value the new value of the variable for the caller thread. 7 */ 8 public void set(T value) { 9 Thread currentThread = Thread.currentThread(); 10 Values values = values(currentThread); 11 if (values == null) { 12 values = initializeValues(currentThread); 13 } 14 values.put(this, value); 15 }
到這個地方就很明顯了 看第9行,
Thread currentThread = Thread.currentThread();
這也就是為什麼說一個執行緒只能有一個looper。也能說明Looper和執行緒的繫結 就是在這個方法裡面完成的。有興趣的同學還可以繼續看values這個內部類,我們在這裡先不去挖的太深。
說完prepare 方法 我們再說說loop方法,因為有很多人都不明白 為什麼loop方法以後的語句 都不執行。我們還是直接上原始碼。
1 /** 2 * Run the message queue in this thread. Be sure to call 3 * {@link #quit()} to end the loop. 4 */ 5 public static void loop() { 6 Looper me = myLooper(); 7 if (me == null) { 8 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 9 } 10 MessageQueue queue = me.mQueue; 11 12 // Make sure the identity of this thread is that of the local process, 13 // and keep track of what that identity token actually is. 14 Binder.clearCallingIdentity(); 15 final long ident = Binder.clearCallingIdentity(); 16 17 while (true) { 18 Message msg = queue.next(); // might block 19 if (msg != null) { 20 if (msg.target == null) { 21 // No target is a magic identifier for the quit message. 22 return; 23 } 24 25 long wallStart = 0; 26 long threadStart = 0; 27 28 // This must be in a local variable, in case a UI event sets the logger 29 Printer logging = me.mLogging; 30 if (logging != null) { 31 logging.println(">>>>> Dispatching to " + msg.target + " " + 32 msg.callback + ": " + msg.what); 33 wallStart = SystemClock.currentTimeMicro(); 34 threadStart = SystemClock.currentThreadTimeMicro(); 35 } 36 37 msg.target.dispatchMessage(msg); 38 39 if (logging != null) { 40 long wallTime = SystemClock.currentTimeMicro() - wallStart; 41 long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; 42 43 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 44 if (logging instanceof Profiler) { 45 ((Profiler) logging).profile(msg, wallStart, wallTime, 46 threadStart, threadTime); 47 } 48 } 49 50 // Make sure that during the course of dispatching the 51 // identity of the thread wasn't corrupted. 52 final long newIdent = Binder.clearCallingIdentity(); 53 if (ident != newIdent) { 54 Log.wtf(TAG, "Thread identity changed from 0x" 55 + Long.toHexString(ident) + " to 0x" 56 + Long.toHexString(newIdent) + " while dispatching to " 57 + msg.target.getClass().getName() + " " 58 + msg.callback + " what=" + msg.what); 59 } 60 61 msg.recycle(); 62 } 63 } 64 }
6-10行 我們能看出來 是取得了 looper的 訊息佇列,然後17行開始 就是一個while true迴圈了!這也就能解釋為啥loop方法一呼叫我們loop後面的程式碼就不會執行,
18行也能看出來,程式碼告訴我們是不斷的在訊息佇列裡面取訊息,並且有可能會阻塞~
我們再來看一下這個37行的程式碼
msg.target.dispatchMessage(msg);
到這個地方 可能很多人就能猜到了,這個地方就是我們處理訊息的地方。那麼這個msg.target我們應該怎麼理解?(很多人無法理解looper handler 之間的關係 其實是因為這個地方始終理解不了)
我們可以先放一放,先去看我們handler的程式碼,在我們文中開頭的第一個例子中,我們在prepare()以後 就建立了一個handler,
我們去看看handler的建構函式。
1 /** 2 * Default constructor associates this handler with the queue for the 3 * current thread. 4 * 5 * If there isn't one, this handler won't be able to receive messages. 6 */ 7 public Handler() { 8 if (FIND_POTENTIAL_LEAKS) { 9 final Class<? extends Handler> klass = getClass(); 10 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 11 (klass.getModifiers() & Modifier.STATIC) == 0) { 12 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 13 klass.getCanonicalName()); 14 } 15 } 16 17 mLooper = Looper.myLooper(); 18 if (mLooper == null) { 19 throw new RuntimeException( 20 "Can't create handler inside thread that has not called Looper.prepare()"); 21 } 22 mQueue = mLooper.mQueue; 23 mCallback = null; 24 }
17-21行 可以看出來,我們在呼叫handler的建構函式的時候,會先取當前執行緒的looper 如果取不到就會報異常了~~
然後我們發訊息的時候是呼叫的send函式,
1 /** 2 * Sends a Message containing only the what value, to be delivered 3 * after the specified amount of time elapses. 4 * @see #sendMessageDelayed(android.os.Message, long) 5 * 6 * @return Returns true if the message was successfully placed in to the 7 * message queue. Returns false on failure, usually because the 8 * looper processing the message queue is exiting. 9 */ 10 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 11 Message msg = Message.obtain(); 12 msg.what = what; 13 return sendMessageDelayed(msg, delayMillis); 14 }
經過一番調查,我們發現最終都是呼叫的這個方法
1 /** 2 * Enqueue a message into the message queue after all pending messages 3 * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 4 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 5 * You will receive it in {@link #handleMessage}, in the thread attached 6 * to this handler. 7 * 8 * @param uptimeMillis The absolute time at which the message should be 9 * delivered, using the 10 * {@link android.os.SystemClock#uptimeMillis} time-base. 11 * 12 * @return Returns true if the message was successfully placed in to the 13 * message queue. Returns false on failure, usually because the 14 * looper processing the message queue is exiting. Note that a 15 * result of true does not mean the message will be processed -- if 16 * the looper is quit before the delivery time of the message 17 * occurs then the message will be dropped. 18 */ 19 public boolean sendMessageAtTime(Message msg, long uptimeMillis) 20 { 21 boolean sent = false; 22 MessageQueue queue = mQueue; 23 if (queue != null) { 24 msg.target = this; 25 sent = queue.enqueueMessage(msg, uptimeMillis); 26 } 27 else { 28 RuntimeException e = new RuntimeException( 29 this + " sendMessageAtTime() called with no mQueue"); 30 Log.w("Looper", e.getMessage(), e); 31 } 32 return sent; 33 }
注意看 24行,
msg.target = this;
然後我們回到loop方法裡面
msg.target.dispatchMessage(msg);
一下就能看出來,其實target就是handler。
所以loop方法裡面處理訊息實際上就是呼叫的handler的dispatchMessage 這個方法!
我們進去看這個方法
1 /** 2 * Handle system messages here. 3 */ 4 public void dispatchMessage(Message msg) { 5 if (msg.callback != null) { 6 handleCallback(msg); 7 } else { 8 if (mCallback != null) { 9 if (mCallback.handleMessage(msg)) { 10 return; 11 } 12 } 13 handleMessage(msg); 14 } 15 }
看14行,發現其實呼叫的是handler的這個方法
1 /** 2 * Subclasses must implement this to receive messages. 3 */ 4 public void handleMessage(Message msg) { 5 }
而這個方法 也是我們每次都去重寫的。到這裡 我們就算是理清楚了 handler 和looper 之間訊息傳遞的一個過程。
其實就是 先呼叫looper.prepare() 然後才能建立handler. 一個執行緒只能有一個looper 一個執行緒佇列 messagequeue.
handler發訊息的時候 發message的時候 實際上是把自己(handler本身)放在了message的 target變數裡面,這樣在loop
方法裡面無線迴圈的時候 我們才能回撥到 handler的handleMessage方法~~~~
同樣的我們也可以分析一下 為什麼quit方法 可以讓loop迴圈結束?(我就不分析了 留給大家自己分析 其實也是不難的)
搞清楚looper和handler的關係以後 我們就可以看看 AsyncTask這個東西。
1 package com.example.asynctest; 2 3 import android.app.Activity; 4 import android.app.ProgressDialog; 5 import android.os.AsyncTask; 6 import android.os.Bundle; 7 import android.os.Handler; 8 import android.os.Looper; 9 import android.util.Log; 10 import android.widget.TextView; 11 12 public class MainActivity extends Activity { 13 14 private TextView tv1; 15 16 @Override 17 protected void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 setContentView(R.layout.activity_main); 20 tv1 = (TextView) this.findViewById(R.id.tv1); 21 /** 22 * Task的例項必須在UI thread中建立; execute方法必須在UI thread中呼叫; 23 * 不要手動的呼叫onPreExecute(), 24 * onPostExecute(Result),doInBackground(Params...), 25 * onProgressUpdate(Progress...)這幾個方法; 該task只能被執行一次,否則多次呼叫時將會出現異常; 26 */ 27 new MyAsyncTask().execute(); 28 29 } 30 31 private class MyAsyncTask extends AsyncTask<Void, Integer, Void> { 32 33 @Override 34 protected void onPreExecute() { 35 // TODO Auto-generated method stub 36 Log.v("mainactivity", Thread.currentThread().getName() 37 + " onPreExecute "); 38 } 39 40 /** 41 * 這裡不能直接操作ui 因為不是在主執行緒裡操作的 42 */ 43 @Override 44 protected Void doInBackground(Void... params) { 45 // TODO Auto-generated method stub 46 // 模擬資料的載入,耗時的任務 47 for (int i = 0; i < 100; i++) { 48 try { 49 Thread.sleep(80); 50 } catch (InterruptedException e) { 51 e.printStackTrace(); 52 } 53 publishProgress(i); 54 } 55 56 Log.v("mainactivity", Thread.currentThread().getName() 57 + " doInBackground "); 58 return null; 59 } 60 61 /** 62 * 在主執行緒執行 63 */ 64 @Override 65 protected void onProgressUpdate(Integer... values) { 66 tv1.setText(values[0] + ""); 67 Log.v("mainactivity", Thread.currentThread().getName() 68 + " onProgressUpdate "); 69 } 70 71 /** 72 * 可以操作ui 73 */ 74 @Override 75 protected void onPostExecute(Void result) { 76 // 進行資料載入完成後的UI操作 77 tv1.setText("LOAD DATA SUCCESS "); 78 Log.e("mainactivity", Thread.currentThread().getName() 79 + " onPostExecute "); 80 } 81 } 82 83 }
我們看一下 日誌和執行效果。
看一下日誌
04-30 09:04:16.345: V/mainactivity(935): main onPreExecute 04-30 09:04:16.494: V/mainactivity(935): main onProgressUpdate 04-30 09:04:16.884: V/mainactivity(935): main onProgressUpdate 04-30 09:04:16.914: V/mainactivity(935): main onProgressUpdate 04-30 09:04:16.914: V/mainactivity(935): main onProgressUpdate 04-30 09:04:16.914: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.264: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.264: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.284: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.284: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.365: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.414: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.414: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.484: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.534: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.614: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.684: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.754: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.834: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.914: V/mainactivity(935): main onProgressUpdate 04-30 09:04:17.994: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.074: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.154: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.244: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.324: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.404: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.484: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.565: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.644: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.724: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.804: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.884: V/mainactivity(935): main onProgressUpdate 04-30 09:04:18.964: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.053: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.134: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.214: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.294: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.375: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.454: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.534: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.614: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.694: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.784: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.864: V/mainactivity(935): main onProgressUpdate 04-30 09:04:19.944: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.024: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.104: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.184: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.264: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.344: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.425: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.504: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.593: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.674: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.754: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.834: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.914: V/mainactivity(935): main onProgressUpdate 04-30 09:04:20.994: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.073: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.154: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.233: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.313: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.404: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.485: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.563: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.643: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.723: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.803: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.883: V/mainactivity(935): main onProgressUpdate 04-30 09:04:21.963: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.043: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.123: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.204: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.293: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.373: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.454: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.533: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.613: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.693: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.773: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.854: V/mainactivity(935): main onProgressUpdate 04-30 09:04:22.934: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.024: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.103: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.184: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.264: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.344: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.424: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.504: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.584: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.664: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.744: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.834: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.914: V/mainactivity(935): main onProgressUpdate 04-30 09:04:23.994: V/mainactivity(935): main onProgressUpdate 04-30 09:04:24.074: V/mainactivity(935): main onProgressUpdate 04-30 09:04:24.154: V/mainactivity(935): main onProgressUpdate 04-30 09:04:24.234: V/mainactivity(935): main onProgressUpdate 04-30 09:04:24.314: V/mainactivity(935): main onProgressUpdate 04-30 09:04:24.394: V/mainactivity(935): main onProgressUpdate 04-30 09:04:24.474: V/mainactivity(935): AsyncTask #5 doInBackground 04-30 09:04:24.474: V/mainactivity(935): main onProgressUpdate
其實還是蠻好理解的,可以清楚的看到
AsyncTask
的執行週期 以及那些方法都是在哪個執行緒執行的(ui還是子?)
然後 我們就來分析一下 這個AsyncTask類到底是怎麼做的?
這是我們呼叫的excute方法,
1 public final AsyncTask<Params, Progress, Result> execute(Params... params) { 2 return executeOnExecutor(sDefaultExecutor, params); 3 }
跟進去 看看。
1 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, 2 Params... params) { 3 if (mStatus != Status.PENDING) { 4 switch (mStatus) { 5 case RUNNING: 6 throw new IllegalStateException("Cannot execute task:" 7 + " the task is already running."); 8 case FINISHED: 9 throw new IllegalStateException("Cannot execute task:" 10 + " the task has already been executed " 11 + "(a task can be executed only once)"); 12 } 13 } 14 15 mStatus = Status.RUNNING; 16 17 onPreExecute(); 18 19 mWorker.mParams = params; 20 exec.execute(mFuture); 21 22 return this; 23 }
3-13行 我們可以看出來,這個excute方法 只能執行一次,不然就要拋異常。同時 也能看出來
onPreExecute(); 這個方法是在主執行緒執行的。
然後我們著重看一下19行,這個地方,mWorker 是什麼?
找了一下 發現
1 private final WorkerRunnable<Params, Result> mWorker;
實際上 是Workerrunnable這個類的物件,我們進去看看這個類。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> { Params[] mParams; }
發現這是一個靜態的抽象類~並且繼承了
Callable 這個介面
當然了 因為這是抽象類,所以我們無需實現這個介面。
既然
mWorker 是 WorkerRunnable 他的物件,哪我們去看看 是如何new出來的呢?看構造方法
1 /** 2 * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 3 */ 4 public AsyncTask() { 5 mWorker = new WorkerRunnable<Params, Result>() { 6 public Result call() throws Exception { 7 mTaskInvoked.set(true); 8 9 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 10 return postResult(doInBackground(mParams)); 11 } 12 }; 13 14 mFuture = new FutureTask<Result>(mWorker) { 15 @Override 16 protected void done() { 17 try { 18 final Result result = get(); 19 20 postResultIfNotInvoked(result); 21 } catch (InterruptedException e) { 22 android.util.Log.w(LOG_TAG, e); 23 } catch (ExecutionException e) { 24 throw new RuntimeException("An error occured while executing doInBackground()", 25 e.getCause()); 26 } catch (CancellationException e) { 27 postResultIfNotInvoked(null); 28 } catch (Throwable t) { 29 throw new RuntimeException("An error occured while executing " 30 + "doInBackground()", t); 31 } 32 } 33 }; 34 }
到這 我們相信 mWorker大家已經知道是怎麼回事了 5-12行表明了mWorker 是一個物件,並且他的回撥方法裡面 也呼叫了
doInBackground 這個方法,至與
postResult 這個方法 我們可以等會再看,先往下面繼續看,我們再拿到
mWorker 這個物件以後 又利用他 去初始化了
mFuture 這個物件,且這個物件是由
FutureTask 這個類生成的,哪我們就去看看這個類。
public class FutureTask<V> implements RunnableFuture<V> {
發現 這類 繼承自 RunnableFuture 這個介面,哪我們去看看這個介面,
public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
我們發現原來 看似複雜的FutureTask 也不過就是一個Runnable 物件嗎~~
回到excute方法
我們發現了 這句話
exec.execute(mFuture);
實際上 就是這麼呼叫的
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
那麼我們趕緊去看一下 sDefaultExecutor 這是什麼東西?
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
再看看
SERIAL_EXECUTOR 這是什麼?
/** * An {@link Executor} that executes tasks one at a time in serial * order. This serialization is global to a particular process. */ public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
原來是一個靜態的 final 物件~~且這個物件是由SerialExecutor 這個類生成的,哪我們趕緊去看一下這個類,
1 private static class SerialExecutor implements Executor { 2 final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); 3 Runnable mActive; 4 5 public synchronized void execute(final Runnable r) { 6 mTasks.offer(new Runnable() { 7 public void run() { 8 try { 9 r.run(); 10 } finally { 11 scheduleNext(); 12 } 13 } 14 }); 15 if (mActive == null) { 16 scheduleNext(); 17 } 18 } 19 20 protected synchronized void scheduleNext() { 21 if ((mActive = mTasks.poll()) != null) { 22 THREAD_POOL_EXECUTOR.execute(mActive); 23 } 24 } 25 }
第二行 明顯的 是建立了一個執行緒佇列
當執行excute方法的時候
實際上就是把這個runnable 先放到執行緒佇列裡面,然後再去執行執行緒佇列裡的第一個執行緒,
20-24行 就是從這個執行緒佇列裡面取值,如果能取到 就執行這句話
THREAD_POOL_EXECUTOR.execute(mActive);
而THREAD_POOL_EXECUTOR就是一個執行緒池。
1 /** 2 * An {@link Executor} that can be used to execute tasks in parallel. 3 */ 4 public static final Executor THREAD_POOL_EXECUTOR 5 = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, 6 TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
也可以看一下這個常量
1 private static final int CORE_POOL_SIZE = 5; 2 private static final int MAXIMUM_POOL_SIZE = 128; 3 private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(10);
有興趣的可以看下這個執行緒池的引數設定。
但實際上我們回到
SerialExecutor
這個類的5=15行
我們發現 實際上我們還是從佇列裡面取任務出來做,任務做完了,才去取下一個任務。
所以 AsyncTask 他本質上還是一個單執行緒執行的 東西,(當然執行的時候是在子執行緒 而不是主執行緒執行的)
我們再回到一開始的地方
1 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, 2 Params... params) { 3 if (mStatus != Status.PENDING) { 4 switch (mStatus) { 5 case RUNNING: 6 throw new IllegalStateException("Cannot execute task:" 7 + " the task is already running."); 8 case FINISHED: 9 throw new IllegalStateException("Cannot execute task:" 10 + " the task has already been executed " 11 + "(a task can be executed only once)"); 12 } 13 } 14 15 mStatus = Status.RUNNING; 16 17 onPreExecute(); 18 19 mWorker.mParams = params; 20 exec.execute(mFuture); 21 22 return this; 23 }
實際上我們執行的 就是mFuture 這個任務,這個任務在子執行緒裡面被執行。
所以我們去看一下FutureTask 他的run方法
1 /** 2 * Sets this Future to the result of its computation 3 * unless it has been cancelled. 4 */ 5 public void run() { 6 sync.innerRun(); 7 }
找到run方法
1 void innerRun() { 2 if (!compareAndSetState(READY, RUNNING)) 3 return; 4 5 runner = Thread.currentThread(); 6 if (getState() == RUNNING) { // recheck after setting thread 7 V result; 8 try { 9 result = callable.call(); 10 } catch (Throwable ex) { 11 setException(ex); 12 return; 13 } 14 set(result); 15 } else { 16 releaseShared(0); // cancel 17 } 18 }
可以看出來 run方法實際執行的是
callable.call 這個方法,所謂這個方法 不過也是我們一開始建構函式裡的mWorker物件罷了,
1 public AsyncTask() { 2 mWorker = new WorkerRunnable<Params, Result>() { 3 public Result call() throws Exception { 4 mTaskInvoked.set(true); 5 6 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 7 return postResult(doInBackground(mParams)); 8 } 9 }; 10 11 mFuture = new FutureTask<Result>(mWorker) { 12 @Override 13 protected void done() { 14 try { 15 final Result result = get(); 16 17 postResultIfNotInvoked(result); 18 } catch (InterruptedException e) { 19 android.util.Log.w(LOG_TAG, e); 20 } catch (ExecutionException e) { 21 throw new RuntimeException("An error occured while executing doInBackground()", 22 e.getCause()); 23 } catch (CancellationException e) { 24 postResultIfNotInvoked(null); 25 } catch (Throwable t) { 26 throw new RuntimeException("An error occured while executing " 27 + "doInBackground()", t); 28 } 29 } 30 }; 31 }
所以執行緒中執行的是3-8行裡的程式碼!!!!!!!!!!!!!!!!!!!!!!!!!!
所以doInBackground 這方法是在子執行緒裡面去執行的。
執行完畢以後才呼叫了下面的方法
1 private Result postResult(Result result) { 2 Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, 3 new AsyncTaskResult<Result>(this, result)); 4 message.sendToTarget(); 5 return result; 6 }
最終我們找到這個handler裡面看一下 看看這裡面做了什麼。
1 private static class InternalHandler extends Handler { 2 @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) 3 @Override 4 public void handleMessage(Message msg) { 5 AsyncTaskResult result = (AsyncTaskResult) msg.obj; 6 switch (msg.what) { 7 case MESSAGE_POST_RESULT: 8 // There is only one result 9 result.mTask.finish(result.mData[0]); 10 break; 11 case MESSAGE_POST_PROGRESS: 12 result.mTask.onProgressUpdate(result.mData); 13 break; 14 } 15 } 16 }
再看看這個finish方法
1 private void finish(Result result) { 2 if (isCancelled()) { 3 onCancelled(result); 4 } else { 5 onPostExecute(result); 6 } 7 mStatus = Status.FINISHED; 8 }
於是 整個AsyncTask的生命週期 就全部得到印證,執行順序 到這裡也就差不多了。
至此 我們 AsyncTask,Looper,Handler 這三者的原始碼分析 也就告一段落。
---恢復內容結束---