Android中的观察者模式:消息分发器(MessageDispatcher)

这个功能是在公司项目需求的时候写出来,本来是基础命令字模式的,但是个人喜欢对象,所有后来在一个小项目中使用时,改成了基于对象模式。

首先,是一个接口,我们称之为监听器:

[html] view
plain
copyprint?

  1. /**
  2. *
  3. * @author poet
  4. *
  5. */
  6. public interface MessageObserver<T> {
  7. void onMessage(T t);
  8. }

这里使用的是泛型,泛型<T>除了作为实际监听的对象类型,也作为监听器管理的key,届时,你将收到一个具体类型的对象。下面是关键代码:

[java] view
plain
copyprint?

  1. package com.poet.lib.base.data;
  2. import java.lang.reflect.ParameterizedType;
  3. import java.lang.reflect.Type;
  4. import java.util.HashMap;
  5. import java.util.HashSet;
  6. import java.util.Map;
  7. import java.util.Set;
  8. import android.os.Handler;
  9. import android.os.Looper;
  10. /**
  11. * 基于对象的消息分发器
  12. * @author poet
  13. *
  14. */
  15. public class MessageDispatcher {
  16. private static Handler sHandler;
  17. private static Map<Class<?>, Set<MessageObserver<?>>> sMap;
  18. /**
  19. * 分发消息(可以在子线程调用)
  20. * @param t
  21. * @return 是否有监听器监听该消息
  22. */
  23. public static <T> boolean dispatch(final T t) {
  24. if (t == null) {
  25. throw new IllegalArgumentException("参数不可为null");
  26. }
  27. final Set<MessageObserver<?>> set;
  28. if (sMap == null || (set = sMap.get(t.getClass())) == null
  29. || set.isEmpty()) {
  30. return false;
  31. }
  32. if (sHandler == null) {
  33. sHandler = new Handler(Looper.getMainLooper());
  34. }
  35. sHandler.post(new Runnable() {
  36. @Override
  37. public void run() {
  38. synchronized (MessageDispatcher.class) {
  39. for (MessageObserver<?> item : set) {
  40. @SuppressWarnings("unchecked")
  41. MessageObserver<T> ob = (MessageObserver<T>) item;
  42. ob.onMessage(t);
  43. }
  44. }
  45. }
  46. });
  47. return true;
  48. }
  49. public synchronized static void addObserver(MessageObserver<?> ob) {
  50. Class<?> clazz = checkObserver(ob);
  51. if (sMap == null) {
  52. sMap = new HashMap<Class<?>, Set<MessageObserver<?>>>();
  53. }
  54. Set<MessageObserver<?>> set = sMap.get(clazz);
  55. if (set == null) {
  56. sMap.put(clazz, set = new HashSet<MessageObserver<?>>());
  57. }
  58. set.add(ob);
  59. }
  60. public synchronized static void removeObserver(MessageObserver<?> ob) {
  61. Class<?> clazz = checkObserver(ob);
  62. Set<MessageObserver<?>> set = sMap.get(clazz);
  63. if (set != null) {
  64. set.remove(ob);
  65. if (set.isEmpty()) {
  66. sMap.remove(clazz);
  67. set = null;
  68. }
  69. }
  70. }
  71. private static Class<?> checkObserver(MessageObserver<?> ob) {
  72. Class<?> clazz;
  73. if (ob == null || (clazz = getGenericClass(ob)) == null) {
  74. throw new IllegalArgumentException("参数不可为null,或没有使用范型");
  75. }
  76. return clazz;
  77. }
  78. private static Class<?> getGenericClass(Object obj) {
  79. try {
  80. ParameterizedType parameterizedTyped = (ParameterizedType) obj
  81. .getClass().getGenericInterfaces()[0];
  82. Type actualType = parameterizedTyped.getActualTypeArguments()[0];
  83. if (actualType instanceof Class<?>) {
  84. return (Class<?>) actualType;
  85. } else {
  86. Type rawType = ((ParameterizedType) actualType).getRawType();
  87. if (rawType instanceof Class<?>) {
  88. return (Class<?>) rawType;
  89. }
  90. }
  91. } catch (Exception e) {
  92. e.printStackTrace();
  93. }
  94. return null;
  95. }
  96. }

代码很明白了,就说下使用场景和扩展使用:

首先,使用MessageDispatcher前,你要确定自己要监听的对象(大多需要自己设计,不同业务要不同的对象,避免使用通用对象,造成无关的监听器收到消息),这点上,和命令字模型的设计比较,却也是不足之处。

其次,在Android中,很多人比较喜欢在Activity上实现接口,然后MessageDispatcher.addObserver(this),这时就更要注意在onDestory中调用removeObserver方法。

注意,该消息分发器,为了使得可以在子线程中调用,使用了handler,所以按照我目前的水平理解,是可以不分主线程子线程,可以直接调用的。

使用场景

1,、可以在收到服务器消息时,处理完了数据,然后通过该分发器发出消息,如果哪个Activity存在并监听了该消息对象,他将收到具体的消息对象<T>。

2、程序内部,一个界面的操作会影响到其他界面,如列表item点击进入详情,可能需要更新列表item的显示。当然这个可以在onActivityResult中处理,也可以发送广播,甚至你可以使用public static
的方法(见过一个同事这么使用,把我气的。。)。不过想来,我们这个消息分发器,倒是符合广播的部分思想:添加监听(注册广播),分发消息(发送广播)。只是我们的这个消息是完全无序的广播,并没有拦截功能,如果你们项目需要,可以给MessageObserver的onMessage方法添加返回值,并在MessageDispatcher中对MessageObserver添加优先级的管理。

3、其实在程序中,任何需要联动和沟通的地方,都可以使用这种机制。但是如果是业务比较复杂,感觉还是命令字模式比较理想,虽然我不喜欢管理命令字和根据命令字对对象进行解析转换。

最后,MessageDispatcher中getGenericClass方法使用反射,主要为了方便获取监听对象<T>的Class,这个也可以通过在MessageObserver添加一个方法由实现类提供。

不足之处,欢迎指正。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-31 22:23:00

Android中的观察者模式:消息分发器(MessageDispatcher)的相关文章

自制Android中的短息备份器源码

短信的实体bean package com.examp.backsms.domain; public class SmsInfo { private String address; private String date; private String type; private String body; public SmsInfo() { } public SmsInfo(String address, String date, String type, String body) { thi

Android中的Handler消息机制

转自:http://blog.csdn.net/liuhe688/article/details/6407225 在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListener { private TextView stateText; private Button btn; @Override public void onCreate(Bundle

Android 中的观察者模式Observer

转载请注明出处:http://blog.csdn.net/feiduclear_up/article/details/42167487 观察者模式"定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖于它的对象都将得到通知,并自动更新",可以理解成多个观察者向一个被观察者订阅消息,当被观察者发生改变时通知相应的观察者去作自己的事情.Android 中的观察者 实现Observer接口,被观察者继承Observable类.使用步骤如下: 1.观察者DataWatch

一个demo让你彻底理解Android中触摸事件的分发

注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOWN.ACTION_MOVE.ACTION_UP.当用户手指接触屏幕时,便产生一个动作为ACTION_DOWN的触摸事件,此时若用户的手指立即离开屏幕,会产生一个动作为ACTION_UP的触摸事件:若用户手指接触屏幕后继续滑动,当滑动距离超过了系统中预定义的距离常数,则产生一个动作为ACTION_MO

关于android中事件传递和分发的一些小理解

android中 当我们的手指触摸屏幕将产生一个事件, (假设 这个过程中如果没有显示的去拦截该事件的话)   这个事件会逐级传递到视图的最底层,即使在中间某些视图会响应这个事件( 这个视图也不会去消费这个事件),     仍然是会传递到底层(底层不响应该事件),然后再由底层回传到顶层,在传回顶层的过程中 ,   原先会响应该事件的视图才会去消费这个事件 例如在左图中                                 A                               

muduo Dispatcher消息分发器 通过多态和模板进行向上类型转换

所谓消息分发(muduo 中,就是接收到buffer之后,额,或者说是 protobuf),在简单的程序设计里面的话,估计就是 type-switch 了,但是这样的话,肯定就不好扩展维护啦. 最后的方法就是,可以根据 type-name 自动去调用相应的方法. typedef boost::function<void (Message*)> ProtobufMessageCallback; 这个算是一个映射咯.muduo 中采用的是 map<Descriptor*,ProtobufMe

android中常用的布局管理器

Android中的几种常用的布局,主要介绍内容有: View视图 RelativeLayout    相对布局管理器 LinearLayout     线性布局管理器 FrameLayout     真布局管理器 TableLayout     表格布局管理器 GridLayout     网格布局管理器 (1) View在XML文件中的常用属性定义: layout_margin:指定该视图与周围视图之间的空白距离(包括上下左右),(可分别写成layout_marginTop.layout_ma

Android中View的事件分发机制

简介 事件也称MotionEvent,事件分发机制就是对MotionEvent事件的分发过程,即当一个MotionEvent发生之后,系统需要把这个事件传递给一个具体的View. 点击事件的分发过程由三个函数共同完成: dispatchTouchEvent(DTE) - 进行事件的分发,如果时间能够传递给当前View,该方法会被调用,返回结果受当前view的onTouchEvent, 子View的dispatchTouchEvent影响,表示是否消耗当前事件. onInterceptTouchE

Android中View的事件分发机制——Android开发艺术探索笔记

欢迎转载,转载请注明出处http://blog.csdn.net/l664675249/article/details/50738102 介绍 点击事件的事件分发就是对MotionEvent事件的分发过程,当一个MotionEvent产生了以后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发的过程. 涉及到的三个方法 dispatchTouchEvent:用来进行事件的分发,如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEve