編輯:關於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核數,當前負載等因素,給出合適的線程解決方案(啟動新線程還是復用老線程)。而自己啟動線程的方案,由於不能獲取上述信息,所以不可能進行任何系統級的優化。因此,建議在能用異步任務的情況下,還是盡量用異步任務來解決問題。
Android中使用ImageLoader加載圖片
Android上讓人頭疼的莫過於從網絡上獲取圖片,然後顯示圖片,最後還要考慮到圖片的回收問題,這之間只要有任何一個環節有問題都可能直接OOM。尤其在需要展示圖片的列表頁面
詳解Android 教你打造高效的圖片加載框架
1、概述優秀的圖片加載框架不要太多,什麼UIL , Volley ,Picasso,Imageloader等等。但是作為一名合格的程序猿,必須懂其中的實現原理,於是乎,今
Android利用懸浮按鈕實現翻頁效果
今天給大家分享下自己用懸浮按鈕點擊實現翻頁效果的例子。首先,一個按鈕要實現懸浮,就要用到系統頂級窗口相關的WindowManager,WindowManager.Layo
andorid自定義ViewPager之——子ViewPager滑到邊緣後直接滑動父ViewPager
最近的項目中,有一個需求要用ViewPager中嵌套ViewPager去實現整個效果,沒做任何處理做出來後,只能不停的滑動子ViewPager,父ViewPager就無法