標籤:
在第二篇文章《Android中利用Handler實現訊息的分發機制(一)》中,我們講到主線程的Looper是Android系統在啟動App的時候,已經幫我們建立好了,而假設在子線程中須要去使用Handler的時候,我們就須要顯式地去調用Looper的 prepare方法和loop方法,從而為子線程建立其唯一的Looper。
詳細代碼例如以下:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId()); ... } } }; Looper.loop(); } }
而實際上,Android SDK 中已經提供了這樣一個實現,一個叫做HandlerThread 的類,它繼承了線程,而且在其run方法中調用了Looper.prepare() 和 Looper.loop() 方法,從而建立了一個已經有Looper的線程,如以下代碼所看到的:
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
我們在主線程中定義的Handler所相應的Looper,還是屬於主線程的,那麼事實上就僅僅是實現了在主線程中的非同步處理而已。
而在日常開發中,當我們須要利用Handler在子線程中實現業務的處理的時候,我們就能夠利用HandlerIntent來實現我們的需求。
普通情況下,我們會建立一個類,讓其去繼承HandlerThread, 例如以下:
public class MyHandlerThread extends HandlerThread { public MyHandlerThread(String name) { super(name); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); MyHandlerThread myHandlerThread = new MyHandlerThread("MyHandlerThread"); myHandlerThread.start(); Handler handler = new Handler(myHandlerThread.getLooper(), new Callback() { @Override public boolean handleMessage(Message msg) { Log.v("Test", "id of Thread by Callback : " + Thread.currentThread().getId()); return false; } }); handler.sendEmptyMessage(0); }
在範例中, 建立了一個MyHandlerThead 對象,記得,它是一個線程,所以須要調用其 start 方法,讓線程跑起來。
接著,就須要利用Handler當中一個建構函式Handler(Looper, Callback) ,將HandlerThread線程中的 Looper 賦給handler,而隨之傳入的,則是Handler.Callback的介面實作類別,如上面代碼所看到的。
最後調用 sendMessage方法,相應的結果例如以下:
10-28 17:24:50.438: V/Test(31694): Id of MainThread : 110-28 17:24:50.448: V/Test(31694): id of Thread by Callback : 91617
可見,handleMessage的處理邏輯已經在是在另外一個線程中去跑了。
普通情況下,我們在建立handlerThread的時候,也會順便實現Handler.Callback介面,將我們要實現的代碼邏輯也封裝在此線程中,讓代碼更具有可讀性,例如以下:
public class MyHandlerThread extends HandlerThread implements Callback{ public MyHandlerThread(String name) { super(name); } @Override public boolean handleMessage(Message msg) { Log.v("Test", "id of Thread by Callback : " + Thread.currentThread().getId()); return true; } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); MyHandlerThread myHandlerThread = new MyHandlerThread("MyHandlerThread"); myHandlerThread.start(); Handler handler = new Handler(myHandlerThread.getLooper(), myHandlerThread); handler.sendEmptyMessage(0); }
說到代碼的可讀性,有時候,我們更加看重代碼之間的層次或者說模組化,耦合度等特點。
不同的商務邏輯,不同的功能,應該實如今不同的模組中,而模組與模組之間就能夠通過一個訊息來通訊,而這樣的訊息通訊方式,我們就能夠利用Handler和HandlerThread來實現。
比方,近期做的一個瀏覽器的小Demo,其類圖例如以下:
在當中,我們就利用了MessageDispatcher來存放各個模組的Handler,其結構例如以下:
private static MessageDispatcher mMsgDispatcher; private SparseArray<Handler> mHandlers; ... public void sendMessage(int target, int from, int msgWhat, Object obj){ Handler handler = mHandlers.get(target); if(handler == null){ Logger.v("There is no Handler registered by target " + target); return; } Message msg = handler.obtainMessage(); msg.what = msgWhat; msg.obj = obj; msg.arg1 = from; handler.sendMessage(msg); }; public void registerHanlder(int key, Handler handler){ mHandlers.put(key, handler); } public void unregisterHanlder(int key){ if(mHandlers.get(key) != null){ mHandlers.delete(key); } } public void destroy(){ mHandlers = null; }
在不同的模組實現中, 我們能夠調用registerHandler方法,將其對象的Handler注冊到MessageDispatcher中,然後通過sendMessage方法,指定相應的目標,假設相應的目標模組也向MessageDispatcher,就能夠獲得其Handler,然後利用其Handler來發送訊息,並由其處理。
比方,我們在BookmarkActivity中向BookmarkManager發送訊息,例如以下:
mMessageDispatcher.sendMessage(MessageConstant.TARGET_BOOKMARK_MGR, MessageConstant.TARGET_BOOKMARK_ACTIVITY, MessageConstant.MSG_BOOKMARK_GET_ALL_DIR, sparseArray);
而在BookmarkManager中,當其handler接受到相應的訊息的時候,其就將會進行相應的處理,例如以下:
class BookmarkHandlerThread extends HandlerThread implements Callback{ public BookmarkHandlerThread(String name) { super(name); } @SuppressWarnings("unchecked") public boolean handleMessage(Message msg){ switch(msg.what){ case MessageConstant.MSG_BOOKMARK_GET_ALL_DIR: //Do Something
這樣,我們就行將商務邏輯和資料操作給分開了,實現了對功能編程。
儘管僅僅是一個不是非常成熟的想法,但還是希望可以跟大家分享一下,在設計代碼架構的時候,可以依據功能,業務需求或者基礎架構來進行分層,分塊,實現代碼的松耦合。
結束。
Android中利用Handler實現訊息的分發機制(三)