在Handler基礎篇中講述了Handler原理和使用,下面是從Handler源碼進一步解析Handler。android
1、源碼解析app
1. Handler的構造函數less
1 /** 2 * Use the {@link Looper} for the current thread with the specified callback interface 3 * and set whether the handler should be asynchronous. 4 * 5 * Handlers are synchronous by default unless this constructor is used to make 6 * one that is strictly asynchronous. 7 * 8 * Asynchronous messages represent interrupts or events that do not require global ordering 9 * with respect to synchronous messages. Asynchronous messages are not subject to 10 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 11 * 12 * @param callback The callback interface in which to handle messages, or null. 13 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 14 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 15 * 16 * @hide 17 */ 18 public Handler(Callback callback, boolean async) { 19 if (FIND_POTENTIAL_LEAKS) { 20 final Class<? extends Handler> klass = getClass(); 21 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 22 (klass.getModifiers() & Modifier.STATIC) == 0) { 23 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 24 klass.getCanonicalName()); 25 } 26 } 27 28 mLooper = Looper.myLooper(); 29 if (mLooper == null) { 30 throw new RuntimeException( 31 "Can't create handler inside thread that has not called Looper.prepare()"); 32 } 33 mQueue = mLooper.mQueue; 34 mCallback = callback; 35 mAsynchronous = async; 36 }
在構造函數中有mLooper和mQueue獲取。其中Looper和MessageQueue是如何建立,下面請看Looper源碼async
1 // sThreadLocal.get() will return null unless you've called prepare(). 2 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 3 private static Looper sMainLooper; // guarded by Looper.class 4 5 final MessageQueue mQueue; 6 7 private static void prepare(boolean quitAllowed) { 8 if (sThreadLocal.get() != null) { 9 throw new RuntimeException("Only one Looper may be created per thread"); 10 } 11 sThreadLocal.set(new Looper(quitAllowed)); 12 } 13 14 /** 15 * Initialize the current thread as a looper, marking it as an 16 * application's main looper. The main looper for your application 17 * is created by the Android environment, so you should never need 18 * to call this function yourself. See also: {@link #prepare()} 19 */ 20 public static void prepareMainLooper() { 21 prepare(false); 22 synchronized (Looper.class) { 23 if (sMainLooper != null) { 24 throw new IllegalStateException("The main Looper has already been prepared."); 25 } 26 sMainLooper = myLooper(); 27 } 28 } 29 30 /** 31 * Returns the application's main looper, which lives in the main thread of the application. 32 */ 33 public static Looper getMainLooper() { 34 synchronized (Looper.class) { 35 return sMainLooper; 36 } 37 } 38 39 /** 40 * Run the message queue in this thread. Be sure to call 41 * {@link #quit()} to end the loop. 42 */ 43 public static void loop() { 44 final Looper me = myLooper(); 45 if (me == null) { 46 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 47 } 48 final MessageQueue queue = me.mQueue; 49 50 // Make sure the identity of this thread is that of the local process, 51 // and keep track of what that identity token actually is. 52 Binder.clearCallingIdentity(); 53 final long ident = Binder.clearCallingIdentity(); 54 55 for (;;) { 56 Message msg = queue.next(); // might block 57 if (msg == null) { 58 // No message indicates that the message queue is quitting. 59 return; 60 } 61 62 // This must be in a local variable, in case a UI event sets the logger 63 final Printer logging = me.mLogging; 64 if (logging != null) { 65 logging.println(">>>>> Dispatching to " + msg.target + " " + 66 msg.callback + ": " + msg.what); 67 } 68 69 final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; 70 71 final long traceTag = me.mTraceTag; 72 if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { 73 Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); 74 } 75 final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); 76 final long end; 77 try { 78 msg.target.dispatchMessage(msg); 79 end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); 80 } finally { 81 if (traceTag != 0) { 82 Trace.traceEnd(traceTag); 83 } 84 } 85 if (slowDispatchThresholdMs > 0) { 86 final long time = end - start; 87 if (time > slowDispatchThresholdMs) { 88 Slog.w(TAG, "Dispatch took " + time + "ms on " 89 + Thread.currentThread().getName() + ", h=" + 90 msg.target + " cb=" + msg.callback + " msg=" + msg.what); 91 } 92 } 93 94 if (logging != null) { 95 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 96 } 97 98 // Make sure that during the course of dispatching the 99 // identity of the thread wasn't corrupted. 100 final long newIdent = Binder.clearCallingIdentity(); 101 if (ident != newIdent) { 102 Log.wtf(TAG, "Thread identity changed from 0x" 103 + Long.toHexString(ident) + " to 0x" 104 + Long.toHexString(newIdent) + " while dispatching to " 105 + msg.target.getClass().getName() + " " 106 + msg.callback + " what=" + msg.what); 107 } 108 109 msg.recycleUnchecked(); 110 } 111 } 112 113 /** 114 * Return the Looper object associated with the current thread. Returns 115 * null if the calling thread is not associated with a Looper. 116 */ 117 public static @Nullable Looper myLooper() { 118 return sThreadLocal.get(); 119 }
在Handler的構造函數中,經過Looper.myLooper()方法獲取Looper對象,再經過Looper.mQueue獲取到消息隊列。ide
在Looper中的myLooper()方法中經過ThreadLocal.get()返回的Looper對象,在何時將Looper對象set到ThreadLocal中。是Looper中的prepare方法實現中建立的Looper對象和將Looper對象set到ThreadLocal中。函數
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 }
那麼,MessageQueue是何時建立的,MessageQueue是在Looper的構造函數實現中建立的oop
1 private Looper(boolean quitAllowed) { 2 mQueue = new MessageQueue(quitAllowed); 3 mThread = Thread.currentThread(); 4 }
當使用Handler在將來某個時刻經過UI線程更新UI,那麼這個Handler建立就要在UI線程的Activity中實現,而不能在內部類中實現,post
1 Handler handler = new Handler(new Handler.Callback{});
在Activity中建立Handler時就已經將Handler和UI線程的Looper及MessageQueue關聯。這樣,在使用handler.sendMessage()或者handler.post()時,將消息添加到消息隊列中。ui
那麼,在MessageQueue中的Message,Looper是如何獲取將交給Handler執行的。那麼,就要看Looper中的loop()方法this
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 final Looper me = myLooper(); 7 if (me == null) { 8 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 9 } 10 final 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 for (;;) { 18 Message msg = queue.next(); // might block 19 if (msg == null) { 20 // No message indicates that the message queue is quitting. 21 return; 22 } 23 24 // This must be in a local variable, in case a UI event sets the logger 25 final Printer logging = me.mLogging; 26 if (logging != null) { 27 logging.println(">>>>> Dispatching to " + msg.target + " " + 28 msg.callback + ": " + msg.what); 29 } 30 31 final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; 32 33 final long traceTag = me.mTraceTag; 34 if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { 35 Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); 36 } 37 final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); 38 final long end; 39 try { 40 msg.target.dispatchMessage(msg); 41 end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); 42 } finally { 43 if (traceTag != 0) { 44 Trace.traceEnd(traceTag); 45 } 46 } 47 if (slowDispatchThresholdMs > 0) { 48 final long time = end - start; 49 if (time > slowDispatchThresholdMs) { 50 Slog.w(TAG, "Dispatch took " + time + "ms on " 51 + Thread.currentThread().getName() + ", h=" + 52 msg.target + " cb=" + msg.callback + " msg=" + msg.what); 53 } 54 } 55 56 if (logging != null) { 57 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 58 } 59 60 // Make sure that during the course of dispatching the 61 // identity of the thread wasn't corrupted. 62 final long newIdent = Binder.clearCallingIdentity(); 63 if (ident != newIdent) { 64 Log.wtf(TAG, "Thread identity changed from 0x" 65 + Long.toHexString(ident) + " to 0x" 66 + Long.toHexString(newIdent) + " while dispatching to " 67 + msg.target.getClass().getName() + " " 68 + msg.callback + " what=" + msg.what); 69 } 70 71 msg.recycleUnchecked(); 72 } 73 }
在loop()方法中有一個無限循環,不停的從MessageQueue中獲取Message(Message msg = queue.next()),再經過msg.target.dispatchMessage(msg)將Message分發給對應的Handler執行。
那麼,msg.target的這個target是什麼,去Message類中去看一下這個target是什麼。
1 public final class Message implements Parcelable { 2 /*package*/ Handler target; 3 ... 4 5 }
從上面源碼中能夠看出target就是Handler。那麼,Message是如何持有Handler引用?
1 /** 2 * Pushes a message onto the end of the message queue after all pending messages 3 * before the current time. It will be received in {@link #handleMessage}, 4 * in the thread attached to this handler. 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 sendMessage(Message msg) 11 { 12 return sendMessageDelayed(msg, 0); 13 } 14 15 /** 16 * Sends a Message containing only the what value. 17 * 18 * @return Returns true if the message was successfully placed in to the 19 * message queue. Returns false on failure, usually because the 20 * looper processing the message queue is exiting. 21 */ 22 public final boolean sendEmptyMessage(int what) 23 { 24 return sendEmptyMessageDelayed(what, 0); 25 } 26 27 /** 28 * Sends a Message containing only the what value, to be delivered 29 * after the specified amount of time elapses. 30 * @see #sendMessageDelayed(android.os.Message, long) 31 * 32 * @return Returns true if the message was successfully placed in to the 33 * message queue. Returns false on failure, usually because the 34 * looper processing the message queue is exiting. 35 */ 36 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 37 Message msg = Message.obtain(); 38 msg.what = what; 39 return sendMessageDelayed(msg, delayMillis); 40 } 41 42 /** 43 * Sends a Message containing only the what value, to be delivered 44 * at a specific time. 45 * @see #sendMessageAtTime(android.os.Message, long) 46 * 47 * @return Returns true if the message was successfully placed in to the 48 * message queue. Returns false on failure, usually because the 49 * looper processing the message queue is exiting. 50 */ 51 52 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { 53 Message msg = Message.obtain(); 54 msg.what = what; 55 return sendMessageAtTime(msg, uptimeMillis); 56 } 57 58 /** 59 * Enqueue a message into the message queue after all pending messages 60 * before (current time + delayMillis). You will receive it in 61 * {@link #handleMessage}, in the thread attached to this handler. 62 * 63 * @return Returns true if the message was successfully placed in to the 64 * message queue. Returns false on failure, usually because the 65 * looper processing the message queue is exiting. Note that a 66 * result of true does not mean the message will be processed -- if 67 * the looper is quit before the delivery time of the message 68 * occurs then the message will be dropped. 69 */ 70 public final boolean sendMessageDelayed(Message msg, long delayMillis) 71 { 72 if (delayMillis < 0) { 73 delayMillis = 0; 74 } 75 return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); 76 } 77 78 /** 79 * Enqueue a message into the message queue after all pending messages 80 * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 81 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 82 * Time spent in deep sleep will add an additional delay to execution. 83 * You will receive it in {@link #handleMessage}, in the thread attached 84 * to this handler. 85 * 86 * @param uptimeMillis The absolute time at which the message should be 87 * delivered, using the 88 * {@link android.os.SystemClock#uptimeMillis} time-base. 89 * 90 * @return Returns true if the message was successfully placed in to the 91 * message queue. Returns false on failure, usually because the 92 * looper processing the message queue is exiting. Note that a 93 * result of true does not mean the message will be processed -- if 94 * the looper is quit before the delivery time of the message 95 * occurs then the message will be dropped. 96 */ 97 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 98 MessageQueue queue = mQueue; 99 if (queue == null) { 100 RuntimeException e = new RuntimeException( 101 this + " sendMessageAtTime() called with no mQueue"); 102 Log.w("Looper", e.getMessage(), e); 103 return false; 104 } 105 return enqueueMessage(queue, msg, uptimeMillis); 106 } 107 108 /** 109 * Enqueue a message at the front of the message queue, to be processed on 110 * the next iteration of the message loop. You will receive it in 111 * {@link #handleMessage}, in the thread attached to this handler. 112 * <b>This method is only for use in very special circumstances -- it 113 * can easily starve the message queue, cause ordering problems, or have 114 * other unexpected side-effects.</b> 115 * 116 * @return Returns true if the message was successfully placed in to the 117 * message queue. Returns false on failure, usually because the 118 * looper processing the message queue is exiting. 119 */ 120 public final boolean sendMessageAtFrontOfQueue(Message msg) { 121 MessageQueue queue = mQueue; 122 if (queue == null) { 123 RuntimeException e = new RuntimeException( 124 this + " sendMessageAtTime() called with no mQueue"); 125 Log.w("Looper", e.getMessage(), e); 126 return false; 127 } 128 return enqueueMessage(queue, msg, 0); 129 } 130 131 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 132 msg.target = this; 133 if (mAsynchronous) { 134 msg.setAsynchronous(true); 135 } 136 return queue.enqueueMessage(msg, uptimeMillis); 137 }
從上面源碼中能夠看出,在調用mHandler.sendMessage(msg)方法時,在將Message添加MessageQueue以前,將Handler的this對象傳遞給了Message.target對象。從而在Looper中loop()方法執行過程當中,經過Message.target.dispatchMessage(msg)方法將Message交給Handler執行。
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 }
2. ThreadLocal是什麼?
ThreadLocal是線程內部的一個數據存儲類,能夠在指定線程中存儲數據,數據存儲後,只能在指定的線程中獲取ThreadLocal中存儲的數據。其它線程是不能修改和獲取在指定線程中ThreadLocal對象存儲的數據。
1 public class MainActivity extends Activity 2 { 3 4 private Handler mHandler = new Handler(); 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) 8 { 9 super.onCreate(savedInstanceState); 10 setContentView(R.layout.activity_main); 11 Button enterBtn = (Button) findViewById(R.id.enter); 12 enterBtn.setOnClickListener(new View.OnClickListener() 13 { 14 @Override 15 public void onClick(View v) 16 { 17 18 } 19 }); 20 } 21 }
在Activity中建立一個Handler對象,因爲Java緣由,非靜態Handler在建立時會匿名持有Activity對象引用。 一句話就是在Java類中建立一個非靜態的成員變量,成員變量會匿名的持有外部類的對象引用。
泄漏緣由:靜態內部類持有外部類的匿名引用,致使Activity對象在銷燬時沒法釋放。
解決方法:
1. 在Handler內部將Activity引用改成弱引用;
1 private Handler mHandler = new LeakHandler(this); 2 3 private static class LeakHandler extends Handler { 4 5 private WeakReference<MainActivity> mWeakActivity; 6 7 private LeakHandler(MainActivity activity) { 8 mWeakActivity = new WeakReference<MainActivity>(activity); 9 } 10 11 @Override 12 public void handleMessage(Message msg) { 13 super.handleMessage(msg); 14 } 15 }
2. 將Handler聲明靜態對象;
1 private static Handler mHandler = new Handler();
3. 在Activity的生命週期方法onDestroy()中調用removeCallbacksAndMessage(null)方法;
1 @Override 2 public void onDestroy() { 3 super.onDestroy(); 4 5 mHandler.removeCallbacksAndMessages(null); 6 }
使用removeCallbacksAndMessages(null)方法意圖刪除當前mHandler中指定Message消息。而參數傳null是意圖刪除當前mHandler的消息隊列。
1. Looper
在Handler中建立Looper時,經過調用Looper.myLooper()方法返回Looper對象。
首先,Looper是經過prepare()方法建立Looper對象並將其保存在ThreadLocal中。
而後,經過Looper.loop()方法開啓循環完成消息的分發。
最終,在loop()方法中的無限循環中經過msg.target.dispatchMessage(msg)方法,將Message交給Handler執行。
2. Handler
做用:
(1)發送消息
(2)接收消息
(3)處理消息
3. ThreadLocal
ThreadLocal是在指定線程中數據存儲類,由ThreadLocal存儲的數據,只能由指定線程獲取和刪除及對數據的其它操做。