当前位置: 代码迷 >> Android >> 全栈工厂实训13-Android-消息总线机制
  详细解决方案

全栈工厂实训13-Android-消息总线机制

热度:28   发布时间:2016-04-27 22:01:37.0
全栈工场实训13---Android---消息总线机制

昨天发表的博文讲述了Android中,采用异步任务进行网络请求的内容,在异步任务结束时,采用Handler机制通知原来的Activity进行界面更新,网友 traburiss指出,异步任务的onPostExecute已经在UI线程中了,再用Handler等于要到下一个UI运行周期才能执行,效率会降低不少,而且违反了异步任务的本意。感谢 traburiss的意见,他说得非常正确,我之所以用到Handler,是因为要在Android应用开发中引入消息总线的概念,想基于Handler来做,所以才使用了这个技术,看来是不恰当的。所以在本篇博文中,我把涉及消息总线实现部分,一起讲出来,这样就避免了网友的提出的问题。

首先介绍一下消息总线,消息总线指系统发生的事件,如收到用户注册成功的异步任务完成消息,系统将消息放到消息总线上,对这个消息感兴趣的应用组件,可以订阅这个消息总线,这样当消息发生时,这些组件会得到通知,从而完成消应的操作。引入消息总线技术,其主要优点是可以实现组件间的松耦合,消息生产者不用关心哪个组件会使用这个消息,只需将产生的消息放到消息总线上即可。而消息消费者订阅这个消息总线,当消息发生时,就可以进行相应的处理了。

我们先来看消息总线的实现机制,代码如下所示:

public class WkyMessageBus {	public static void prepareEventBus() {		messageBus = new HashMap<String, HashMap<String, Handler>>();		// 将所有消息类型加到消息总线上		HashMap<String, Handler> registerUserListeners = new HashMap<String, Handler>();		messageBus.put("" + WkyConstants.MSG_WHAT_REGISTER_USER, registerUserListeners);	}		public static void registerToMessageBus(int messageTypeId, String listenerName, Handler handler) {		HashMap<String, Handler> listeners = messageBus.get("" + messageTypeId);		listeners.put(listenerName, handler);	}		public static void unregisterToMessageBus(int messageTypeId, String listenerName) {		HashMap<String, Handler> listeners = messageBus.get("" + messageTypeId);		listeners.remove(listenerName);	}		public static void postMessage(Message msg) {		HashMap<String, Handler> handlers = messageBus.get("" + msg.what);		for (Handler handler : handlers.values()) {			handler.sendMessage(msg);		}	}	private static HashMap<String, HashMap<String ,Handler>> 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核数,当前负载等因素,给出合适的线程解决方案(启动新线程还是复用老线程)。而自己启动线程的方案,由于不能获取上述信息,所以不可能进行任何系统级的优化。因此,建议在能用异步任务的情况下,还是尽量用异步任务来解决问题。


华丽的分隔线
******************************************************************************************************************************************************************************
希望大家多支持,有大家的支持,我才能走得更远,谢谢!
银行账号:622202 0200 1078 56128 闫涛
我的支付宝:[email protected]










  相关解决方案