全棧工場實訓13---Android---訊息匯流排機制

來源:互聯網
上載者:User

全棧工場實訓13---Android---訊息匯流排機制

昨天發表的博文講述了Android中,採用非同步任務進行網路請求的內容,在非同步任務結束時,採用Handler機制通知原來的Activity進行介面更新,網友 traburiss指出,非同步任務的onPostExecute已經在UI線程中了,再用Handler等於要到下一個UI運行周期才能執行,效率會降低不少,而且違反了非同步任務的本意。感謝 traburiss的意見,他說得非常正確,我之所以用到Handler,是因為要在Android應用開發中引入訊息匯流排的概念,想基於Handler來做,所以才使用了這個技術,看來是不恰當的。所以在本篇博文中,我把涉及訊息匯流排實現部分,一起講出來,這樣就避免了網友的提出的問題。

首先介紹一下訊息匯流排,訊息匯流排指系統發生的事件,如收到使用者註冊成功的非同步任務完成訊息,系統將訊息放到訊息匯流排上,對這個訊息感興趣的應用組件,可以訂閱這個訊息匯流排,這樣當訊息發生時,這些組件會得到通知,從而完成消應的操作。引入訊息匯流排技術,其主要優點是可以實現組件間的松耦合,訊息生產者不用關心哪個組件會使用這個訊息,只需將產生的訊息放到訊息匯流排上即可。而訊息消費者訂閱這個訊息匯流排,當訊息發生時,就可以進行相應的處理了。

我們先來看訊息匯流排的實現機制,代碼如下所示:

 

public class WkyMessageBus {public static void prepareEventBus() {messageBus = new HashMap>();// 將所有訊息類型加到訊息匯流排上HashMap registerUserListeners = new HashMap();messageBus.put( + WkyConstants.MSG_WHAT_REGISTER_USER, registerUserListeners);}public static void registerToMessageBus(int messageTypeId, String listenerName, Handler handler) {HashMap listeners = messageBus.get( + messageTypeId);listeners.put(listenerName, handler);}public static void unregisterToMessageBus(int messageTypeId, String listenerName) {HashMap listeners = messageBus.get( + messageTypeId);listeners.remove(listenerName);}public static void postMessage(Message msg) {HashMap handlers = messageBus.get( + msg.what);for (Handler handler : handlers.values()) {handler.sendMessage(msg);}}private static HashMap> messageBus = null;}


 

如上面代碼所示,用messageBus來代表訊息匯流排的集合,Android的Message對象的what值變為字串作為key,其值為一個列表,列表元素為Handler,通過該handler可以向Activity發送訊息,通知相應Activity進行相關操作。

Activity通過registerToMessageBus方法,訂閱到訊息匯流排。在Activity銷毀時調用unregisterToMessageBus方法,從訊息匯流排上登出。

訊息生產者產生訊息後,通過postMessage將訊息發布到訊息匯流排上來。

在應用啟動時,即應用的Application對象的onCreate方法中,初始化訊息匯流排。

 

WkyMessageBus.prepareEventBus();

 

如上篇文章所述,當非同步任務結束時,會發送訊息到訊息匯流排:

 

/** * 非同步任務結束時要調用的方法,通知頁面進行更新 * 【閆濤 2015.09.24】初始版本 */@Overrideprotected void onPostExecute(String result) {JSONObject json = null;long userId = 0;try {json = new JSONObject(result);userId = json.getLong(userId);} catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();}WkyRegisterLoginModel model = (WkyRegisterLoginModel)activity.getModel();model.setUserId(userId);activity.onAsyncTaskResult();Message msg = handler.obtainMessage();msg.what = WkyConstants.MSG_WHAT_REGISTER_USER;Bundle params = new Bundle();params.putString(WkyConstants.MSG_DATA_NAME, result);msg.setData(params);WkyMessageBus.postMessage(msg);}

這段代碼有三個部分,第一部分是更新對應的Model對象中的資料,第二個部分是調用WkyActivity基類所定義JysRegisterLoginActivity重載的onAsyncTaskResult方法,實現介面的更新,第三個部分是產生一個Message對象,並發送到訊息匯流排上去。

 

JysRegisterLoginActivity在啟動時,註冊到訊息匯流排上去,在銷毀時從訊息匯流排登出,代碼如下所示:

 

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(com.weikangyun.wkylib.R.layout.activity_register_login);handler = new JysRegisterLoginHandler(this);messageBusListenerName = this.getClass().getCanonicalName() + System.currentTimeMillis();WkyMessageBus.registerToMessageBus(WkyConstants.MSG_WHAT_REGISTER_USER, messageBusListenerName, handler);getViewObjects();setupGuis();setupActionListeners();}@Overridepublic void onDestroy() {super.onDestroy();WkyMessageBus.unregisterToMessageBus(WkyConstants.MSG_WHAT_REGISTER_USER, messageBusListenerName);}

當系統產生訊息,會向Activity發送訊息,其訊息處理如下所示:

 

 

static protected class JysRegisterLoginHandler extends WkyRegisterLoginHandler {public JysRegisterLoginHandler(JysRegisterLoginActivity activity) {this.activity = activity;}public void handleMessage(Message msg) {super.handleMessage(msg);// 自己額外的處理switch (msg.what) {case WkyConstants.MSG_WHAT_REGISTER_USER:activity.processRegisterUserResult(msg);break;}}private JysRegisterLoginActivity activity = null;}

上面其實還遺留了一個問題,就是非同步訊息結束時更新介面的問題。我們在應用的公用基Activity類WkyActivity中,定義了非同步任務回呼函數onAsyncTaskResult方法,如下所示:

 

 

/** * 當非同步任務完成後,會回調本方法,執行具體的頁面更新操作。需要實現兩部分功能: * 1. 非同步任務:在onPostExecute函數中,將結果放到Activity對應的Model中 * 2. Activity中:從Model中取出資料,更新介面 * 【閆濤 2015.12.04】初始版本 */public void onAsyncTaskResult() {}

在具體的Activity類裡,編寫介面更新函數。注意,在非同步任務結束的方法onPostExecute方法中,我們已經將所需資料更新到Model中,所以onAsyncTaskResult方法只需從Model中讀出資料進行顯示就可以了。

 

這裡在補充一個問題,我們的網路請求為什麼採用非同步任務,而不是直接採用線程技術呢?是因為非同步任務封裝了線程與UI線程之間的互動嗎?其實這隻是其中的一個方面。因為在非同步任務背後,是系統管理的線程池,系統會根據CPU核心數,當前負載等因素,給出合適的線程解決方案(啟動新線程還是複用老線程)。而自己啟動線程的方案,由於不能擷取上述資訊,所以不可能進行任何系統級的最佳化。因此,建議在能用非同步任務的情況下,還是盡量用非同步任務來解決問題。

 

 

 

 

 

 

 



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.