全栈工场实训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]

时间: 2024-07-29 10:05:46

全栈工场实训13---Android---消息总线机制的相关文章

android 消息提示机制

消息提示机制 一 对话框 Dialog AlertDialog 对话框有:标准对话框, 菜单式对话框, 菜单式复选框对话框,自定义对话框 (注意:这里的上下文公用了,代码的点击方法我已经在点击监听事件里注册了) 1 标准对话框: 在布局界面写好按钮,然后设置点击事件, 在事件种创建 dialog 的构造器 AlertDialog.Builder builder = new AlertDialog.Builder(context); 然后用构造器设置dialog的各种属性,最后create,sho

Android消息循环机制

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51707527 Android的消息循环机制主要先关的类有: Handler Looper Message MessageQueue ActivityThread 实际上 应用程序启动的时候,会创建一个UI线程,然后该线程关联一个消息队列,相关操作封装一个个消息放入队列中,主线程会不断循环从队列中取出消息进行分发处理. 为什么用Handler 大家都知道,Android规定[访问UI只

全栈项目|小书架|服务器开发-Koa2中间件机制洋葱模型了解一下

KOA2 是什么? Koa是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小.更富有表现力.更健壮的基石. 通过利用 async函数,Koa帮你丢弃回调函数,并有力地增强错误处理. Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序. 为什么产生? 笔者对这几个框架都不熟,这里就不误人子弟了.可以看看下面一些大佬的介绍. Koa是由Express的原班人马打造,那么他们为什么不将

Android基础知识【项目实训】【3】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 欢迎界面过后,应该显示app的主界面了,根据[UI设计指导]中的规划,主界面采用上下两级标签导航.这部分是app开发中比较麻烦的一块. 1.先来看一下,最终的效果吧,这样做起来比较有底: 默认显示的主界面,下部是主导航,上面是二级导航,默认打开的是"促销打折"这一版面

Android基础知识【项目实训】【1】

[该项目实训是Android基础知识的一个综合练习] [项目题目]:校园订餐App设计 综合案例 [设计目标] 1.必要功能 ?快餐店浏览,与订餐 ?今天订餐活动查询与订餐,特价饭菜预定 ?分类订餐查询,预定 ?常定饭菜  预定 ?健康餐推荐 ?定时预定,提前预定 ?订单查看, ?餐馆与饭菜打分,评价 ?用户注册与登录 2.扩展选择功能 ?快速拨打电话 ?饮食跟踪,热量估算 ?系统设置 [项目说明] 该项目为实际应用项目的单机 简化版本,只需要完成Android平台App的设计与开发工作. Ap

Android基础知识【项目实训】【2】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 因为项目只涉及基础知识,因此项目中所用数据并不联网,都读取单机数据库.(即将该项目中所用数据,如菜品信息.店铺信息等存入数据库)用户在第一次打开该项目时,会在用户手机上创建这些数据库,并插入测试数据. 1.先制作一个欢迎界面,欢迎的同时,准备数据库 欢迎界面Activity对应

Android基础知识【项目实训】【4】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 主界面的功能确实比较复杂,因此上一篇知识说的周边内容.现在开始说这个界面的代码和布局文件. 1.先看一下项目的组织结构吧,要不然不好说他们的关系: (1)db包中的都是跟 数据库相关的 (2)eatall中放的都是activity或者fragment (3)entity中放的实

Android基础知识【项目实训】【5】

[该项目实训是Android基础知识的一个综合练习,特别提示:项目中会用到一些图片素材,都是随意整理的,稍后会上传一个资源,包含该事项项目的基本功能,也含有图片素材] [项目题目]:校园订餐App设计 综合案例 [目标] 主界面中包含两个二级子界面,分别是活动界面和账单界面,下面介绍它们的实现代码和布局文件. 1.下面这个是 活动界面的Activity代码,因为这个界面加载时需要 读取数据库中数据了,所有功能的实现上会涉及到 db那个包中一些类. 注意这个Activity也是继承 Activit

中智讯-开放式智慧教室实训系统建设方案

中智讯(武汉)科技有限公司开放式智慧教室实训系统建设方案 1   智慧教室项目开发背景1.1    互联互通的物联网技术 随着网络覆盖的普及,人们提出了一个问题,既然无处不在的网络能够成为人际间沟通的无所不能的工具,为什么我们不能将网络作为物体与物体沟通的工具,人与物体沟通的工具,乃至人与自然沟通的工具?于是,物联网技术的发展应运而生.物联网是"万物沟通"的.具有全面感知.可靠传送.智能处理特征的连接物理世界的网络,实现了任何时间.任何地点及任何物体的连结.可以帮助实现人类社会与物理世