編輯:關於Android編程
Android消息機制主要指的是Handler的運行機制。
(注意,消息機制中的Handler是android.os包下的Handler,不是java.util.logging包中的Handler,開發中注意不要到錯包。)
Handler是消息機制的上層接口。Handler將任務切換到handler所在的線程執行。
與handler相關的有MessageQueue、Looper。其中,
MessageQueue中文名稱是消息隊列,內部存儲了一組消息,並以隊列的形式向外提供插入刪除操作。MessageQueue以隊列的形式命名,而內部實現是單鏈表。內部提供了next方法讀取一條消息,並從消息隊列中刪除。
Looper是個無限循環,當調用Looper.prepare和Looper.loop方法後Looer就開始工作了。Looper以無限循環方式檢查是否有消息,有就處理,無就等待。Looer中有個ThreadLocal對象,用來存儲每個線程的數據,通過ThreadLocal可以獲取每個線程的Looper,ThreadLocal保證每個線程的數據互不干擾。
流程
Handler創建時,會使用當前線程的Looper來構造內部的消息循環系統。每個Handler對應一個Looper。如果Handler所在的線程沒有對應的Looer,則會拋出一個這樣的異常信息:
Can't create handler inside thread that has not called Looper.prepare()。
解決辦法就是,在Handler創建之前,調用Looper.Prepare初始化looper,並在handler創建後調用Looper.loop開啟循環,若不調用Looper.loop則Looper是無法工作的。
這樣的情況一般出現在子線程創建handler對象的時候。為什麼主線程我們沒有創建Looper對象,卻沒有拋出這樣的異常呢?
原因就是在MainThread中,系統給我們初始化了Looper對象。查看源碼可發現這句:
Looper.prepareMainLooper();//創建主線程Looper和MessageQueue Looper.Loop();//開啟主線程Looper
當調用handler.post(Runnable runnable)方法後,會將Runnable對象投遞到handler內部的Looer中處理。也可以通過Handler.sendMessage(Message msg)方法來發送一個消息,也是會在Looer中處理。查看源碼得知,handler.post方法最終調用的也是handler.send方法來實現的。
當handler.send方法被調用時,它會調用MessageQueue的enqueueMessage將消息存放到MessageQueue中。當Looper檢測到時,會調用next方法讀取此消息,並從MessageQueue中刪除。
相關代碼如下:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
看一下DispatchMessage方法執行流程:
在dispatchMessage方法中有以下幾個分支:
先檢查Message的callback(是一個Runnable類型的對象)是否為null,如果不為null就執行HandlerCallBack來處理消息;
檢查mCallback(是一個CallBack接口類型對象)是否為null,如果不為null,就執行mCallback接口對象的handlerMessage方法來處理消息;
最後則是調用handler的handlerMessage方法來處理消息。
題外話,子線程為什麼不能直接訪問UI?
android的控件不是線程安全的。在線程中訪問ui,可能導致ui不可控。考慮到ui訪問效率又不能是主線程阻塞,故不能采用加鎖機制。所以在
Android 4.0以後做出了這樣的規定,要求子線程不能訪問ui,否則會直接拋出異常。異常信息是這樣的:
Only the original thread that created a view hierarchy can touch its views.
Handler的應用場景
通常在子線程中將結果發送給主線程,通知主線程更新ui。
也可以在主線程中將任務加入到消息隊列順序執行。
源碼分析
//可以直接實現此接口來初始化handler,而不必去實現創建Handler的子類 public interface Callback { public boolean handleMessage(Message msg); } //handlerMessage是一個空方法,子類若要通過這種方式處理消息,子類必須自己實現 public void handleMessage(Message msg) { } //消息處理,分析見上述 public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
下面是handler的幾個構造方法:
public Handler() { this(null, false); } public Handler(Callback callback) { this(callback, false); } //使用指定的Looper對象構造handler public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); } public Handler(boolean async) { this(null, async); } public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class 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 = callback; mAsynchronous = async; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
handler的幾個構造,由於代碼不復雜,這裡不再說明。
接下來看一系列的obtainMessage方法,及它們的重載:
//Message.obtainMessage獲取的結果是通過Message.Target設置的值 public final Message obtainMessage() { return Message.obtain(this); } public final Message obtainMessage(int what) { return Message.obtain(this, what); } public final Message obtainMessage(int what, Object obj) { return Message.obtain(this, what, obj); } public final Message obtainMessage(int what, int arg1, int arg2) { return Message.obtain(this, what, arg1, arg2); } public final Message obtainMessage(int what, int arg1, int arg2, Object obj) { return Message.obtain(this, what, arg1, arg2, obj); }
接著看幾個比較重要的方法:
//post方法與postDelayed方法一樣,最終調用的是sendMessageDelayed方法 public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); } public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } //從消息隊列中移除指定的Runnable對象 public final void removeCallbacks(Runnable r) { mQueue.removeMessages(this, r, null); } //移除消息隊列中的Runnable對象,如果object參數不為null 則會移除所有的 public final void removeCallbacks(Runnable r, Object token) { mQueue.removeMessages(this, r, token); }
下面是sendmessage的一系列方法,
//將消息添加到消息隊列,如果添加成功會返回true,否則返回false public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } //將一個僅有what值的message添加到消息隊列,添加成功返回true,否則返回false public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } //在指定的時間後發送一個僅有what值的message,添加到消息隊列 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } //在指定的時間將僅有what值的message添加到消息隊列 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } 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) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
//將消息加入消息隊列 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } //從消息隊列中移除指定what值的message public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); } public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object); } public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); }
接下來的代碼,是創建了一個IMessager的實現類。可以看出使用了Binder機制。為了實現對使用Messenger跨進程發送消息的處理。涉及到進程通信,這裡先不多講。
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } } private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; } private static void handleCallback(Message message) { message.callback.run(); } final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger;
Android RecyclerView 是Android5.0推出來的,導入support-v7包即可使用。個人體驗來說,RecyclerView絕對是一款功能強大的控
8月9日,晴。“江城如畫裡,山曉望晴空。雨水夾明鏡,雙橋落彩虹。 人煙寒橘柚,秋色老梧桐。” 上篇已經讓飛機加載子彈和音效及背景音樂,本篇主要添加敵機。
在這篇文章中,我將介紹如何實現列表中的視頻播放。在流行的應用,如Facebook,Instagram的或Magisto的工作原理相同:Facebook的:Ma
android手機怎麼修改hosts。相信很多android手機用戶都會碰到過Google賬號無法登陸的問題。而無法登入安卓市場的情況。我們電腦可以修改電腦