Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 全棧工場實訓13---Android---消息總線機制

全棧工場實訓13---Android---消息總線機制

編輯:關於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);
	}

這段代碼有三個部分,第一部分是更新對應的Model對象中的數據,第二個部分是調用WkyActivity基類所定義JysRegisterLoginActivity重載的onAsyncTaskResult方法,實現界面的更新,第三個部分是產生一個Message對象,並發送到消息總線上去。

 

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);
	}

當系統產生消息,會向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核數,當前負載等因素,給出合適的線程解決方案(啟動新線程還是復用老線程)。而自己啟動線程的方案,由於不能獲取上述信息,所以不可能進行任何系統級的優化。因此,建議在能用異步任務的情況下,還是盡量用異步任務來解決問題。

 

 

 

 

 

 

 



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved