編輯:關於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上讓人頭疼的莫過於從網絡上獲取圖片,然後顯示圖片,最後還要考慮到圖片的回收問題,這之間只要有任何一個環節有問題都可能直接OOM。尤其在需要展示圖片的列表頁面
1、概述優秀的圖片加載框架不要太多,什麼UIL , Volley ,Picasso,Imageloader等等。但是作為一名合格的程序猿,必須懂其中的實現原理,於是乎,今
今天給大家分享下自己用懸浮按鈕點擊實現翻頁效果的例子。首先,一個按鈕要實現懸浮,就要用到系統頂級窗口相關的WindowManager,WindowManager.Layo
最近的項目中,有一個需求要用ViewPager中嵌套ViewPager去實現整個效果,沒做任何處理做出來後,只能不停的滑動子ViewPager,父ViewPager就無法