所要用到的android源碼路徑:
ActivityThread源碼路徑:android-4.0.3_r1\frameworks\base\core\java\android\app\ActivityThread
Activity源碼路徑:android-4.0.3_r1\frameworks\base\core\java\android\app\Activity
Handler源碼路徑:android-4.0.3_r1\frameworks\base\core\java\android\os\Handler
Looper源碼路徑:android-4.0.3_r1\frameworks\base\core\java\android\os\Looper
Message源碼路徑:android-4.0.3_r1\frameworks\base\core\java\android\os\Message
MessageQueue源碼路徑:android-4.0.3_r1\frameworks\base\core\java\android\os\MessageQueue
我們從使用handler發送一條message到接收進行處理的這個過程來理解Handler,Looper,MessageQueue的實現,在Activity主線程中,會默認
創建一個Looper對象,在這個Looper類中會創建一個MessageQueue的消息隊列,然後主線程會調用Looper的的loop()方法循環遍歷這個消息隊
列,如果有消息則會通過Handler對象將消息傳遞到handlerMessage方法中進行處理,如果Hanlder對象爲空也就是沒有創建Hanlder對象則會將
這條消息丟掉。那麼消息的發送是怎樣的呢?我們創建一個Handler對象,使用這個對象發送Message,其實是使用Looper對象傳遞進來的
MessageQueue,通過這個消息隊列的引用將Message放進消息隊列中,由於Looper會遍歷這個隊列,所以Handler對象發送msg,將其放進消
息隊列,Looper遍歷消息隊列將消息取出,然後傳遞給Hanlder進行處理,這樣一個消息的發送與接收就完成了。
首先我們根據Handler的構造函數來了解Handler的幾種使用方法,從API中我們知道Handler有四個構造函數,分別是:
Handler()
Handler(callback)
Handler(looper)
Handler(looper, callback)
一、不帶參數的Handler()構造函數,其使用的是主線程默認的Looper對象以及MessageQueue
Handler handler2 = new Handler(){
public void handleMessage(Message msg) {
};
};
handler2.sendEmptyMessage(30);
直接在Activity中new一個Handler對象,並且重載handlerMessage方法就能夠實現Message的發送與接收。
二、Handler(callback)構造函數,帶了一個Hanlder類中的一個Callable接口對象作爲參數,看源碼就能夠很清楚知道,他的作用其實是將handlerMessage
方法給獨立出去,也就是在Activity中如果handlerMessage中的代碼量太多,使用這個構造函數去創建對象,就能夠將handlerMessage方法不放在
Activity中。
public class MyHandler implements Handler.Callback{
@Override
public boolean handleMessage(Message arg0) {
return false;
}
}
先實現Hanlder.Callback接口,叢雜handlerMessage方法,在這裏進行消息的處理
MyHandler callback = new MyHandler();
Handler handler3 = new Handler(callback);
handler3.sendEmptyMessage(20);
在Activity中創建Handler對象,將Callback對象作爲參數傳遞進去,然後使用handler發送Message,就能夠在MyHandler中接收消息進行處理。
三、Handler(looper)構造函數,帶了一個自定義的Looper對象作爲參數,所以我們只要自定義一個Looper,然後將該Looper對象傳遞進去就能夠正常
的進行消息發送與接收。但是我們不必要真的去自定義一個Looper類,我們只需要繼承android已經實現好的HandlerThread線程,就能夠自定義一個
Looper類
public class MyThread extends HandlerThread{
//HandlerThread類是android中已經繼承Thread的類,他已經幫你實現了Looper對象的創建
//所以如果我們在實現Handler時,需要自定義Looper對象,則直接繼承此類就行。
public MyThread(String name) {
super(name);
}
@Override
protected void onLooperPrepared() {
//這個方法是在Looper.loop()被調用前在線程HandlerThread的run方法中被調用
//所以如果要在這之前做什麼操作,就需要重載這個方法
Log.i("MyThread", "onLooperPrepared");
super.onLooperPrepared();
}
}
MyThread thread = new MyThread("thread");
thread.start();
Looper looper = thread.getLooper();
Handler handler1 = new Handler(looper){
public void handleMessage(Message msg) {
}
};
handler1.sendEmptyMessage(10);
這樣我們就能夠使用自定義的Looper進行消息的發送與接收,而不必使用Activity幫我們已經創建好的默認的Looper對象。
四、Handler(looper, callback)構造函數,知道了前面三種構造函數之後,這種就能夠很容易理解了:使用自定義Looper,將handlerMessage方法
從創建Handler對象的類中獨立出去。
Handler的詳細使用方法就介紹完了,接下來我們就來分析相關類的源碼,來徹底瞭解其運作過程。
首先我們來看看Looper的實現過程,我們知道在創建一個Activity時,其主UI主線程ActivityThread中會默認創建一個Looper對象,那麼這個對象是在
什麼地方創建的呢?
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
step1:從上面ActivityThread源碼中我們可以看見,這個main方法是主線程的啓動的地方,首先他調用了Looper的靜態prepareMainLooper()方法:
public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
public static Looper myLooper() {
return sThreadLocal.get();
}
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
在上面源碼中我們可以看出,prepareMainLooper方法中調用prepare()方法創建了一個Looper對象,並將這個Looper對象放進了ThreadLocal中,將
Looper對象放進ThreadLocal中的作用是,ThreadLocal會維護Looper對象中變量的副本。具體可以參考ThreadLocal的使用方法。然後調用myLooper
方法從ThreadLocal中獲取Looper對象,並將其賦值給主線程Looper對象的引用。在Looper構造函數中我們可以看見,他創建了一個MessageQueue
對象,同時獲取了Looper對象所在當前線程的引用。這樣一個Looper對象便創建成功。
step2: 然後判斷主線程的Handler是否爲空,如果爲空則默認創建一個Handler對象,但是在源碼中這個默認的Handler時候從來就沒使用過,
估計是既然已經默認創建了Looper,那麼也默認創建一個Handler對象。
step3: 創建主線程ActivityThread對象,然後調用loop()方法
public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// 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);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
msg.target.dispatchMessage(msg);
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
// 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();
}
}
}
在loop方法中,首先獲取之前創建的Looper對象,MessageQueue對象,清除所有之前的訪問標誌,然後下面就是一個while死循環,在這個while循環
中,通過Message msg = queue.next()不停的從消息隊列中獲取Message,然後判斷獲取的Message是否爲空,不爲空,則判斷這個Message的target
是否爲空,通過了解Message源碼我們知道,這個target其實就是一個Handler對象,也就是如果在沒有創建Handler對象,則這個Message不進行處理
直接返回,繼續去下一個Message。如果已經創建了Handler對象,則通過msg.target.dispatchMessage(msg)將從消息隊列中獲取的Message傳遞
到Handler中。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在dispatchMessage中將消息傳遞到handlerMessage(msg)中,這樣handler便接收到了一個Message。
通過上面三步,當一個Activity啓動時,其主線程ActivityThread創建成功後,會默認創建一個Looper對象,一個消息隊列。同時會循環遍歷這個消息
隊列,而不會管Handler對象有沒有創建。
下面我們來看Handler是怎樣發送一個消息進消息隊列的,首先了解Hanlder的初始化過程:
public Handler() {
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 = null;
}
從Handler的構造函數中我們可以看到,通過Looper.myLooper()獲取Looper對象的引用,通過mLooper.mQueue獲取消息隊列的引用。
接下來我們看發送消息的方法:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
從上面源碼可以看到,調用sendMessage其實是調用sendMessageDelayed方法,在sendMessageDelayed方法中調用了sendMessageAtTime方法
sendMessageAtTime纔是最終發送Message的地方,在sendMessageAtTime中我們可以看到,首先判斷消息隊列的引用是否爲空,不爲空則調用
enqueueMessage方法將Message放進消息隊列中。在這個方法中我們還可以看到通過msg.target = this,Message獲取到了當前Handler對象的引用
final boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
要理解enqueueMessage源碼,就必須結合Looper獲取消息的方法來理解:
final Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
final Message msg = mMessages;
if (msg != null) {
final long when = msg.when;
if (now >= when) {
mBlocked = false;
mMessages = msg.next;
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
} else {
nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
}
} else {
nextPollTimeoutMillis = -1;
}
// If first time, then get the number of idlers to run.
if (pendingIdleHandlerCount < 0) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
在enqueueMessage中我們看到,首先判斷Message的target即所屬的Handler對象是否爲空,爲空則拋出RuntimeException異常,然後定義了一個
final boolean needWake變量,注意他沒有進行初始化,而且爲final類型,表明一旦其被初始化後就無法再次進行更改了,然後就是一個同步塊,在
這個同步塊中,首先獲取一個全局Message對象mMessages的引用,如果這個Message不是延遲性或者空的消息,那麼將這個msg賦值給這個全局
的Message對象mMessages,並且將mBlocked賦值給needWake,在MessageQueue源碼中,可以看見mBlocked定義時是沒有初始化的,那麼
在哪裏初始化呢?這就要看next()方法了。
我們知道在主UI線程創建時,Looper對象就會創建,就會調用loop()方法,就會調用next()方法循環遍歷消息隊列,由於一開始消息隊列爲空,所以
msg一定爲空,執行的只是下面這段代碼:
if (pendingIdleHandlerCount < 0) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
從這裏就能夠看見,mBlocked一開始是初始化爲true的,所以在同步方法塊執行完畢後,會調用nativeWake方法。在next()方法中可以看見,其消息
操作的邏輯也是一個同步方法塊,而且注意到了沒有?他操作的Message不是從什麼隊列中獲取的,其實操作的就是那個全局的Message對象
mMessages,並且從MessageQueue的其他removeMessages等方法可以看到,所有操作全局對象mMessages都是在方法同步塊中的,所以我們
就應該能夠明白了MessageQueue不是用什麼消息隊列來保存Message的,而只是使用一個全局的mMessages來保存的,每次Looper循環遍歷的
都是mMessages對象,獲取到之後然後將這個對象置爲空,如果next()在調用,則其他方法調用處於阻塞狀態,如果enqueueMessage處於調用中
則其他調用的方法處於阻塞中,所以當有多個線程同時調用同一個Handler對象發送Message時,其中只有一個線程調用的方法是處於運行狀態的,
其他線程的調用是處於阻塞狀態的,爲什麼android會這樣進行處理呢?我覺得這麼處理的原因是以時間換取空間,Handler發送消息的邏輯是相對
簡單的,沒有什麼業務邏輯,也就是所需獲取執行的時間是非常短的,而且不會出現很多線程同時使用同一個Handler來發送Message。
所以到這裏我們就明白了MessageQueue的實現機制了:
1、MessageQueue不是什麼消息隊列,沒有使用到隊列,其使用的是一個全局對象來進行消息接收與發送
2、MessageQueue中所有的消息操作方法都是同步塊的,當有一個方法被執行時,其他方法是處於阻塞狀態的。
3、如果我們同時開啓非常多的線程使用同一Handler發送消息或者移除消息,那麼sendMessage(msg)不會立即返回結果的。
4、在多個線程中不要大量使用Handler來操作Message。他只適合於少量線程中進行使用。
這樣Handler的消息發送以及Looper的消息獲取就都剖析完了。Handler,Looper,MessageQueue的實現也就完全講完了。
總結:
在我們創建一個Activity時,會自動創建一個Looper對象,並且在Looper的構造方法中會創建一個MessageQueue的對象,當Activity的主線程啓動
時,會調用Looper的loop()方法循環檢查MessageQueue中的全局對象mMessages是否爲空,如果不爲空則會調用相應Handler的
dispatchMessage方法,將這個消息傳遞到Handler中的handleMessage方法中進行處理。當我們創建一個Handler對象,使用這個Handler對象
發送消息時,最終調用的是MessageQueue中的enqueueMessage,消息的所有的操作,如:發送,移除,遍歷都是在MessageQueue中進行
操作的,這也對應了面向對象的及迪米特法則,也就是所有該類的職責應該就在該類中完成,儘量少於外界進行聯繫。消息的處理是單個操作的
當一個消息在發送時,其他消息的發送是處於阻塞狀態,由於消息操作的業務邏輯簡單,所以不必過於關注消息操作的延時性,但是不應在大量
線程中使用Handler進行消息傳遞。