标签:
昨天发表的博文讲述了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); }
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核数,当前负载等因素,给出合适的线程解决方案(启动新线程还是复用老线程)。而自己启动线程的方案,由于不能获取上述信息,所以不可能进行任何系统级的优化。因此,建议在能用异步任务的情况下,还是尽量用异步任务来解决问题。
华丽的分隔线
******************************************************************************************************************************************************************************
希望大家多支持,有大家的支持,我才能走得更远,谢谢!
银行账号:622202 0200 1078 56128 闫涛
我的支付宝:yt7589@hotmail.com
标签:
原文地址:http://blog.csdn.net/yt7589/article/details/50173717