Android 小话设计模式 之 从观察者到EventBus和RxJava

  设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

前言

软件工程中的23种设计模式,相信大家耳熟能详,在大Java中完美适用,直接上图(自己画的):


Android 小话设计模式 之 从观察者到EventBus和RxJava_第1张图片
Design Pattern.png

  这里主要给大家介绍一下神奇且常见的观察者模式,及其引申出的一些强大用法:CallBack,EventBus,RxJava。

观察者模式

观察者模式(Observer)完美的将观察者和被观察的对象分离开,定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
  简单的来说,打个比方,就类似于狱警时时刻刻盯着犯人,犯人作出一点小动作,那么狱警便立马做出回应,反之则相安无事。在Android中的点击事件监听setOnClickListener( )便完成对接这一概念,即:观察者将自己注册到被观察对象中,被观察对象将观察者存放在一个容器里。被观察对象发生了某种变化时,从容器中得到所有注册过的观察者,将变化通知观察者从而达到一个时时监听的作用。
  观察者(Observer)模式,又叫做发布订阅(Publish/Subscribe)模式,下面给出一张经典的观察者模式的关系对应图,看完大致都明白了吧~


Android 小话设计模式 之 从观察者到EventBus和RxJava_第2张图片
Observer Pattern.png

强大的应用之处

观察者模式相信大家都有了一个了解,在Android中最基本的实现就是对点击事件的监听了,相信网上关于观察者与setOnClickListener( )的关系介绍有很多很多咯,这里介绍两种更高级的应用场景,看完你便会完美体会到其强大之处!


Android 小话设计模式 之 从观察者到EventBus和RxJava_第3张图片
Observer Relation.png
  • EventBus

EventBus是Android下高效的发布/订阅事件总线机制。是基于JVM内部的数据传输系统,其核心对象为Event和EventHandler。作用是可以代替传统的Intent,Handler,Broadcast或接口函数在Fragment,Activity,Service,线程之间传递消息,优点是开销小,代码更优雅,以及将发送者和接收者解耦。
  看完概念是不是感觉强大的EventBus已经无所不能了!那么就从源码层面分析下其强大的原因:
  汗!在看源码之前还是先看一下用法吧:

0、Prepare:

  Gradle:
        compile 'org.greenrobot:eventbus:3.0.0'
  Maven:
        
              org.greenrobot
              eventbus
              3.0.0
        

1、定义关系:写一个类描述被观察者和观察者之间统一事件关系,可以为空,也可以加上参数并通过get/set方法绑定。

  public class Event { 
        public Event() {
              // TODO
        } 
  }

2、接收事件页面:注册与销毁。

  @Override  
  protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        // 注册EventBus  
        EventBus.getDefault().register(this);  
  }

  // TODO

  @Override  
  protected void onDestroy(){  
        super.onDestroy();  
        // 销毁EventBus  
        EventBus.getDefault().unregister(this);
  }  

3、发布事件页面:将之前定义在事件关系的类发布。

  EventBus.getDefault().post(new Event());

4、接收事件页面:重写onEvent...( )方法,通过注解的方法鉴别类型,接收消息(4种方式)。

  @Subscribe(threadMode = ThreadMode.MainThread) 
  //在ui线程执行 
  public void onEvent(Event event) { 
          // TODO
  }

  @Subscribe(threadMode = ThreadMode.BackgroundThread) 
  //在后台线程执行 
  public void onEvent(Event event) { 
        // TODO
  }

  @Subscribe(threadMode = ThreadMode.Async) 
  //强制在后台执行 
  public void onEvent(Event event) { 
        // TODO
  }

  @Subscribe(threadMode = ThreadMode.PostThread) 
  //默认方式, 在发送线程执行 
  public void onEvent(Event event) { 
        // TODO
  }

综上,一个Event就对应一个关系,在发布与接收者之间通过该标识的Event就可以自动识别作出响应。参考一下3.0之前在接收页面的接收方法,对应上面的(注:在EventBus3.0已经将原有的方法改版):

   - onEventMainThread():
        不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行。
        在Android中只能在UI线程中更新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。

  - onEventBackgroundThread():
        如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行。
        如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。

  - onEventAsync():
        无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync()。

  - onEvent():
        发布事件和接收事件线程在同一个线程。
        使用这个方法时,在onEvent方法中不能执行耗时操作。
        如果执行耗时操作容易导致事件分发延迟。

下面简单分析一下源码,参考了鸿洋大神的帖子,从register( )方法入手,先看getDefault( ):

  /** Convenience singleton for apps using a process-wide EventBus instance. */
  public static EventBus getDefault() {
        if (defaultInstance == null) {
              synchronized (EventBus.class) {
                    if (defaultInstance == null) {
                          defaultInstance = new EventBus();
                    }
              }
        }
        return defaultInstance;
  }

使用了双重判断的方式,防止并发的问题,还能极大的提高效率。再看一下普通的register( )方法:

  public void register(Object subscriber) {
        register(subscriber, DEFAULT_METHOD_NAME, false, 0);
  }

  public void register(Object subscriber, int priority) {
        register(subscriber, DEFAULT_METHOD_NAME, false, priority);
  }

  public void registerSticky(Object subscriber) {
        register(subscriber, DEFAULT_METHOD_NAME, true, 0);
  }

  public void registerSticky(Object subscriber, int priority) {
        register(subscriber, DEFAULT_METHOD_NAME, true, priority);
  }

再点进去看看内部核心的register(subscriber...)方法:

  private synchronized void register(Object subscriber, String methodName, boolean sticky, int priority) {
        List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), methodName);
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
              subscribe(subscriber, subscriberMethod, sticky, priority);
        }
  }

即遍历该类内部所有方法,然后根据methodName去匹配,匹配成功的封装成SubscriberMethod,最后返回一个List。继续深入的subscribe( )方法在这里就不贴代码了,有兴趣的童鞋可以自己无限往下点点看。
  register( )方法的核心便是:扫描了所有的方法,把匹配的方法最终保存在subscriptionsByEventType( )中,该方法中的eventType是我们方法参数的Class,Subscription中则保存着subscriber,subscriberMethod(method, threadMode, eventType),priority,包含了执行改方法所需的一切。
  其余的一些post( )方法等其实的本质与上方类似,关于整个EventBus的流程可以大致梳理如下:EventBus负责订阅对象与事件的管理,比如注册、注销以及发布事件等。在初始时将某个对象注册到EventBus中,EventBus会遍历该对象class中的所有方法,把参数数量为1且用了Subscriber注解标识的函数管理起来,以事件类型和订阅函数Subscriber的tag构建一个EventType作为一种事件类型,某个事件类型对应有一个接收者列表。当有事件发布时,EventBus会根据发布的事件类型与tag构建EventType,然后找到对应的订阅者列表,并且将这些事件投递给所有订阅者。SubscriberMethodHunter负责查找合适的EventType,而EventHandler则负责将这些订阅函数执行到相应的线程中。

  • RxJava

Reactive Extensions编程简称Rx编程,又叫响应式编程,提供一致的编程接口,帮助开发者更方便的处理异步数据流,使软件开发更高效、更简洁。其中,对于异步错误处理,传统的try/catch没办法处理异步计算,Rx提供了合适的错误处理机制轻松使用并发。而Rx的Observables和Schedulers让开发者可以摆脱底层的线程同步和各种并发问题。
  关于RxJava的基本实现很简单,看如下三步:

1、创建一个Observable对象,直接调用Observable.create( ):

  Observable myObservable = Observable.create(
        new Observable.OnSubscribe() {
              @Override
              public void call(Subscriber sub) {
                    sub.onNext("Hello, world!");
                    sub.onCompleted();
              }
        }
  );

2、创建一个Subscriber来处理Observable对象发出的字符串:

  Subscriber mySubscriber = new Subscriber() {
        @Override
        public void onNext(String s) { 
              System.out.println(s); 
        }

        @Override
        public void onCompleted() {
              // TODO
        }

        @Override
        public void onError(Throwable e) {
              // TODO
        }
  };

3、通过subscribe函数就可以将myObservable对象和mySubscriber对象关联绑定起来,完成subscriber对observable的订阅:

  myObservable.subscribe(mySubscriber);

当然,强大的RxJava提供了一些方法使代码简化,如just( ),map( ),Action1类等等,如:

  Observable.just("Hello, world!")
        .subscribe(new Action1() {
              @Override
              public void call(String s) {
                    System.out.println(s);
              }
        });

  Observable.just("Hello, world!")
        .map(new Func1() {
              @Override
              public String call(String s) {
                    return s + "Ivor";
              }
        }).subscribe(new Action1() {
              @Override
              public void call(String s) {
                    System.out.println(s);
              }
        });

关于RxJava的基本使用大致就介绍到这里,后续关于RxJava和Retrofit以及RxAndroid的引申下期会更新,大家也可以提前参考一下福生宝宝的RxJava 的使用与理解(二)。

  • EventBus VS RxJava

RxJava要比EventBus的应用更广泛,EventBus仅仅是作为一种消息的传递工具,但是RxJava里面几乎可以做任何事情,只是对于简单的业务来说可能有些冗余,EventBus相对来说更加轻量,EventBus有个缺点就是凡是使用了EventBus的类都不能进行混淆了,否则Evnetbus就找不到OnEvent方法了。

尾声

关于观察者模式的应用有很多,这里先介绍这么两种强大的库,供大家参考学习~~请将强大的Observer与Listener发挥到极致:)

  • 附在线流程图制作网站
    https://www.processon.com

  • Android EventBus源码解析 带你深入理解EventBus
    http://blog.csdn.net/lmj623565791/article/details/40920453

  • RxJava 的使用与理解(一)
    http://www.jianshu.com/p/f564104958b8

  • Github地址:
    https://github.com/Ivorfason

  • Github博客:
    http://ivorfason.github.io

  • 新浪博客
    http://blog.sina.com.cn/u/1780835484

  • 个人网站:
    http://www.ivorfason.site

  • 个人邮箱:(我觉得QQ邮箱很高大上,You can you up!)
    [email protected]

  • 杂谈一下
      这里只是简单的给大家介绍了一下用法和基本的实现方式,大家可以直接拿来写Demo,在实际应用中,一个简单的EventBus便可省去许多代码,一个简单的RxJava便可省去许多逻辑,但是自己写的时候还会有一些坑要踩,合理地应用好观察者模式,你会变得很强大!You can you up!

你可能感兴趣的:(Android 小话设计模式 之 从观察者到EventBus和RxJava)