編輯:關於Android編程
Android的消息機制幾乎是面試必問的話題,當然也並不是因為面試,而去學習,更重要的是它在Android的開發中是必不可少的,占著舉足輕重的地位,所以弄懂它是很有必要的。下面就來說說最基本的東西。
Looper
作用:
關聯起Thread
循環取出消息
1、Looper是否可以直接實例化?
Looper構造方法是私有的,其中做了兩件事
創建一個MessageQueue
得到與之對應的Thread
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2、一個線程能對應多個Lopper?
不能,一個線程對應一個Looper對象,通過ThreadLocal保證一個線程只有一個Looper與之對應,如果多次調用Looper.prepare();則會拋出運行時異常。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { // 查看是否有looper與當前線程對應
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
3、Looper是無限循環,會阻塞嗎?
是,當開啟一個loop後是一個死循環,從MessageQueue中取出消息,處理消息,但是也有可能退出,在沒有消息後退出循環。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 略
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) { // 當沒有消息的時候,退出
// No message indicates that the message queue is quitting.
return;
}
// 略
msg.target.dispatchMessage(msg);
}
4、可以再次調用Looper.prepareMainLooper嗎?
不可以,Looper.prepareMainLooper最終也是調用prepare(),同2.
public static void prepareMainLooper() {
prepare(false); // 創建一個Looper
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
5、MainLooper什麼時候創建的?
MainLooper是啟動Activity創建ActivityThread(並不是一個Thread)時候創建,所以不能多次創建。
public static void main(String[] args) {
// 略
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
// 略
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 略
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 略
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
Handler
作用:
發送消息到MessageQueue
處理消息
1、Handler如何與Looper、MessageQueue關聯起來?
我們知道一個Looper對應一個Thread,一個Looper包含一個MessageQueue。當我們創建Handler時就會從當前線程中取出與之對應的Looper,讓後在從Looper中取出MessageQueue。
// 1、自動獲取
public Handler(Callback callback, boolean async) {
// 略
mLooper = Looper.myLooper(); // 取出當前線程中的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 取出MessageQueue
mCallback = callback;
mAsynchronous = async;
}
// 2、傳遞一個Looper進來
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Message
單項鏈表結構。
作用:
數據的載體
1、消息如何復用的?
從全局消息池(鏈表結構)中
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
2、Message為什麼能傳遞?
Android中想要傳遞對象要麼實現Serializable要麼Parcelable,在這裡是實現了Parcelable接口。
public final class Message implements Parcelable {
// 略
}
3、如何與Handler關聯?
我們知道在消息傳機制中Handler充當著“快遞員”的角色,那麼他又是如何與“貨物”--Message發生關系呢?實際上Message有一個成員變量target他的類型正是Handler,
/*package*/ Runnable callback; public int arg1; public int arg2; public Object obj; /*package*/ Handler target; // 關鍵點
當我們通過Handler去send一個Message時候最終都會為target賦值為this,即當前的Handler。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 賦值語句
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
另為如果是通過Message.Obtain(),獲取的復用Message也會為其賦值。
多說一句,Handler.obtainMessage()調用的就是Message.Obtain()。
public final Message obtainMessage(){
return Message.obtain(this);
}
總結:
通過一系列的包涵關系,最終Looper、Handler、Message、MessageQueue即發生關聯,從而形成一個閉合,開啟消息循環。

困惑
最近一直在看這方面的知識,但是能力有限,還是有不少困惑,如果有錯誤,或你理解下面的問題請聯系我fvaryu@qq.com,願與君交流學習,謝謝
1、Message中的sPool,哪裡初始化的?為什麼Message.obtain()中不會拋異常?
2、ActivityThread並不是線程,為什麼可以創建一個Looper,Main Thread什麼時候創建?
3、為什麼序列化了的對象就可以傳遞?與Binder有關?
4、MessageQueue對應的是NativeMessageQueue,具體實現需要學習?
5、Loop.loop(),會退出嗎?退出時機是什麼?如果會退出,那麼主線程同樣會退出嗎?
以上就是對Android 消息機制的資料整理,後續繼續補充相關資料,謝謝大家對本站的支持
android自定義GifView顯示gif動畫
gif動畫在web開發中使用的非常的多,利用gif,許多動畫不必再用程序編寫,現在有非常多的App已經使用到了gif動畫,可是android sdk並沒有為我們提供gif
Android開源框架Image-Loader詳解
如果說評價一下哪個圖片開源庫最被廣泛使用的話,我想應該可以說是Universal-Image-Loader,在主流的應用中如果你隨便去反編譯幾個,基本都能看到他的身影,它
淺談android適配(下)
上一篇我們主要了解了為什麼適配,以及怎麼適配,同時給出了部分切圖規范,和在開發過程中需要的一些注意事項,這一遍主要從官方給出的指導建議出發,從視覺的角度來說說怎麼適配。度
Android仿京東首頁輪播文字效果
京東客戶端的輪播文字效果:本次要實現的只是後面滾動的文字(前面的用ImageView或者TextView實現即可),看一下實現的效果實現思路上圖只是一個大概的思路,要實現