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

来源:互联网 发布:摄影测量数据处理软件 编辑:程序博客网 时间:2024/04/30 23:18

昨天发表的博文讲述了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】初始版本 */@Overrideprotected 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 blocke.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在启动时,注册到消息总线上去,在销毁时从消息总线注销,代码如下所示:

@Overrideprotected 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();}@Overridepublic 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 闫涛
我的支付宝:yt7589@hotmail.com










6 1
原创粉丝点击