編輯:關於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;
淺談RecyclerView(完美替代ListView,GridView)
Android RecyclerView 是Android5.0推出來的,導入support-v7包即可使用。個人體驗來說,RecyclerView絕對是一款功能強大的控
第四十天 一樂在其中—Android的小游戲打飛機(三)添加敵機
8月9日,晴。“江城如畫裡,山曉望晴空。雨水夾明鏡,雙橋落彩虹。 人煙寒橘柚,秋色老梧桐。” 上篇已經讓飛機加載子彈和音效及背景音樂,本篇主要添加敵機。
(更新版)Android VideoPlayer 在滾動列表實現item視頻播放(ListView控件和RecyclerView)
在這篇文章中,我將介紹如何實現列表中的視頻播放。在流行的應用,如Facebook,Instagram的或Magisto的工作原理相同:Facebook的:Ma
Android手機修改HOSTS方法|Android系統如何修改hosts文件
android手機怎麼修改hosts。相信很多android手機用戶都會碰到過Google賬號無法登陸的問題。而無法登入安卓市場的情況。我們電腦可以修改電腦