編輯:關於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】初始版本
*/
@Override
protected 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 block
e.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);
}
JysRegisterLoginActivity在啟動時,注冊到消息總線上去,在銷毀時從消息總線注銷,代碼如下所示:
@Override
protected 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();
}
@Override
public void onDestroy() {
super.onDestroy();
WkyMessageBus.unregisterToMessageBus(WkyConstants.MSG_WHAT_REGISTER_USER, messageBusListenerName);
}
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;
}
/**
* 當異步任務完成後,會回調本方法,執行具體的頁面更新操作。需要實現兩部分功能:
* 1. 異步任務:在onPostExecute函數中,將結果放到Activity對應的Model中
* 2. Activity中:從Model中取出數據,更新界面
* 【闫濤 2015.12.04】初始版本
*/
public void onAsyncTaskResult() {
}
這裡在補充一個問題,我們的網絡請求為什麼采用異步任務,而不是直接采用線程技術呢?是因為異步任務封裝了線程與UI線程之間的交互嗎?其實這只是其中的一個方面。因為在異步任務背後,是系統管理的線程池,系統會根據CPU核數,當前負載等因素,給出合適的線程解決方案(啟動新線程還是復用老線程)。而自己啟動線程的方案,由於不能獲取上述信息,所以不可能進行任何系統級的優化。因此,建議在能用異步任務的情況下,還是盡量用異步任務來解決問題。
用Kotlin實現Android定制視圖(KAD 06),kotlinandroid
用Kotlin實現Android定制視圖(KAD 06),kotlinandroid作者:Antonio Leiva 時間:Dec 27, 2016 原文鏈接:https
BLE-NRF51822教程3-sdk程序框架剖析
BLE-NRF51822教程3-sdk程序框架剖析nordicBLE 技術交流群498676838本講為框架介紹,不會牽涉到太多代碼細節。 51822的官方SDK其實是
重寫MPAndroidChart顯示標記
重寫MPAndroidChart顯示標記 MPAndroidChart是實現圖表功能的優秀控件, 可以完成大多數繪制需求. 對於修改第三方庫而言, 優秀的架構是繼承開發,
界面優化處理技術之(三)登錄框表格組件優化處理,表格組件
界面優化處理技術之(三)登錄框表格組件優化處理,表格組件 在res下drawable下創建xml文件 代碼: 1 <?xml version=1.0 encodi