Rx(函数响应式编程) Java,Rx Android,EventBus

来源:互联网 发布:淘宝活动页面代码 编辑:程序博客网 时间:2024/06/09 04:12
> Rx:函数响应式编程,EventBus:事件总线,题主所说的都是两个具体实现库了。对于题主所说的这两个库,看名字就可以感觉出 RxJava 功能更强些了,RxJava 主要做异步、网络的数据处理,强大之处就如@hi大头鬼hi 所说的各种对数据的处理了,而对于处理完后的数据处理是一样的都是观察者模式来通知,也可以把 RxJava 进一步封装出一个 EventBus(RxBus) 库,实现可以参考:Implementing an Event Bus with RxJava 。当然同时使用这两个库也是可以的,并不会冲突,即异步数据处理用 RxJava,操作完成后的事件通知用 EventBus 事件总线库,这个看你心情了。P.S. RxJava 的一大爽点也就是链式调用,代码调用流程异常清晰 ;),如果结合 EventBus 来 post 最终结果的话不是满满的乱入感了吗。

EventBus 这个库也有蛋疼之处:为了性能考虑接收事件的函数都以 onEvent 开头;事件一般都要写个对应的 Event 类出来,导致会都很多这些类,考虑到一个应用中这些事件发布一般也不会很多,在可接受范围就行了。

>  EventBus比较适合仅仅当做组件间的通讯工具使用,主要用来传递消息。使用EventBus可以避免搞出一大推的interface,仅仅是为了实现组件间的通讯,而不得不去实现那一推的接口。
RxJava和EventBus一样也是基于观察者模式,但是使用的场景确实异步数据流的处理。比如下面的例子

Observable.from()
.map((x) -> x + 1)
.filter((x) -> x % 2 == 0)
.subscribe()

通过引入函数式的方式来处理数据流,看起来舒服多了。另外RxJava有大量丰富强大的operator,可以满足你的大部分数据处理需求。RxJava另一个强大的地方就是他的scheduler,你可以为Observable和Subscriber指定不同的执行线程,在Android中,你就可以方便的将Observable指定在IO线程中运行,Subscriber在UI线程中运行。

> RxJava要比EventBus的应用更广泛,EventBus仅仅是作为一种消息的传递工具,但是RxJava里面几乎可以做任何事情。

如果是Android开发的话,可以使用RxAndroid,这是对RxJava的一个扩展,结合sqare公司的retrofit可以很轻松的完成网络的访问。

我们知道,在Android中异步操作一般使用AsycTask来完成,但是AsycTask有很多缺点,如不能方便的终止任务的执行等。

RxAndroid完全可以替代AsycTask来完成各种异步操作,而且还有BindActivity和BindFragment方法,你根本不需要考虑异步操作时的Activity和Fragment的生命周期问题,还有更加强大的的链式调用,可以使程序很简洁。

EventBus有个缺点就是凡是使用了EventBus的类都不能进行混淆了,否则Evnetbus就找不到OnEvent方法了。

以上,推荐使用RxAndroid。

EventBus被作为一种通用模式应用在Android开发中。Otto和EventBus这样的类库经常被用来省去编写不同层之间来封装代码的模板类。尽管EventBus刚开始看起来的确带来了方便,但是很快这些纠缠的事件会被弄成一堆乱麻,很难跟踪更别说调试。

EventBus通常被宣扬可以降低模块之间的耦合度,但是,事实上带给你的是降低耦合度带来的混乱和困惑。

一个常见的弊端是处理嵌套的事件。不要在事件订阅者里面发布事件,这看起来很容易避免,但是经常会不容易理解。一个订阅者很可能会通过调用其他的方法来间接地抛出其他的事件。这样事件会纠缠成一个复杂地难以置信的球,很难进行调试。

Facebook的Flux框架是另外一个事件驱动的设计框架,但是它明令禁止发送嵌套事件。希望Otto和EventBus未来能够检测嵌套事件。

》RxJava正在Android开发者中变的越来越流行。唯一的问题就是上手不容易,尤其是大部分人之前都是使用命令式编程语言。
RxJava最核心的两个东西是Observables(被观察者,事件源)和Subscribers(观察者)。Observables发出一系列事件,Subscribers处理这些事件。这里的事件可以是任何你感兴趣的东西(触摸事件,web接口调用返回的数据。。。)

一个Observable可以发出零个或者多个事件,知道结束或者出错。每发出一个事件,就会调用它的Subscriber的onNext方法,最后调用Subscriber.onNext()或者Subscriber.onError()结束。

Rxjava的看起来很想设计模式中的观察者模式,但是有一点明显不同,那就是如果一个Observerble没有任何的的Subscriber,那么这个Observable是不会发出任何事件的。

 创建一个Observable对象很简单,直接调用Observable.create即可
Observable<String> myObservable = Observable.create(  
    new Observable.OnSubscribe<String>() {  
        @Override  
        public void call(Subscriber<? super String> sub) {  
            sub.onNext("Hello, world!");  
            sub.onCompleted();  
        }  
    }  
);  
这里定义的Observable对象仅仅发出一个Hello World字符串,然后就结束了。接着我们创建一个Subscriber来处理Observable对象发出的字符串。
Subscriber<String> mySubscriber = new Subscriber<String>() {  
    @Override  
    public void onNext(String s) { System.out.println(s); }  
  
    @Override  
    public void onCompleted() { }  
  
    @Override  
    public void onError(Throwable e) { }  
};  
这里subscriber仅仅就是打印observable发出的字符串。通过subscribe函数就可以将我们定义的myObservable对象和mySubscriber对象关联起来,这样就完成了subscriber对observable的订阅。
myObservable.subscribe(mySubscriber);  
一旦mySubscriber订阅了myObservable,myObservable就是调用mySubscriber对象的onNext和onComplete方法,mySubscriber就会打印出Hello World!
更简洁的代码
是不是觉得仅仅为了打印一个hello world要写这么多代码太啰嗦?我这里主要是为了展示RxJava背后的原理而采用了这种比较啰嗦的写法,RxJava其实提供了很多便捷的函数来帮助我们减少代码。
首先来看看如何简化Observable对象的创建过程。RxJava内置了很多简化创建Observable对象的函数,比如Observable.just就是用来创建只发出一个事件就结束的Observable对象,上面创建Observable对象的代码可以简化为一行
Observable<String> myObservable = Observable.just("Hello, world!");  
接下来看看如何简化Subscriber,上面的例子中,我们其实并不关心OnComplete和OnError,我们只需要在onNext的时候做一些处理,这时候就可以使用Action1类。
Action1<String> onNextAction = new Action1<String>() {  
    @Override  
    public void call(String s) {  
        System.out.println(s);  
    }  
};  
subscribe方法有一个重载版本,接受三个Action1类型的参数,分别对应OnNext,OnComplete, OnError函数。
[java] view plain copy
myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction);  
这里我们并不关心onError和onComplete,所以只需要第一个参数就可以
[java] view plain copy
myObservable.subscribe(onNextAction);  
// Outputs "Hello, world!"  
上面的代码最终可以写成这样
Observable.just("Hello, world!")  
    .subscribe(new Action1<String>() {  
        @Override  
        public void call(String s) {  
              System.out.println(s);  
        }  
    });  
使用
java8的lambda可以使代码更简洁
Observable.just("Hello, world!")  
    .subscribe(s -> System.out.println(s));  
Android开发中,强烈推荐使用retrolambda这个gradle插件,这样你就可以在你的代码中使用lambda了。
根据响应式函数编程的概念,Subscribers更应该做的事情是“响应”,响应Observable发出的事件,而不是去修改。如果我能在某些中间步骤中对“Hello World!”进行变换是不是很酷?
  操作符(Operators)
操作符就是为了解决对Observable对象的变换的问题,操作符用于在Observable和最终的Subscriber之间修改Observable发出的事件。RxJava提供了很多很有用的操作符。
比如map操作符,就是用来把把一个事件转换为另一个事件的。
Observable.just("Hello, world!")  
  .map(new Func1<String, String>() {  
      @Override  
      public String call(String s) {  
          return s + " -Dan";  
      }  
  })  
  .subscribe(s -> System.out.println(s));  
使用lambda可以简化为
Observable.just("Hello, world!")  
    .map(s -> s + " -Dan")  
    .subscribe(s -> System.out.println(s));  
是不是很酷?map()操作符就是用于变换Observable对象的,map操作符返回一个Observable对象,这样就可以实现链式调用,在一个Observable对象上多次使用map操作符,最终将最简洁的数据传递给Subscriber对象。
  map操作符进阶
map操作符更有趣的一点是它不必返回Observable对象返回的类型,你可以使用map操作符返回一个发出新的数据类型的observable对象。
比如上面的例子中,subscriber并不关心返回的字符串,而是想要字符串的hash值
Observable.just("Hello, world!")  
    .map(new Func1<String, Integer>() {  
        @Override  
        public Integer call(String s) {  
            return s.hashCode();  
        }  
    })  
    .subscribe(i -> System.out.println(Integer.toString(i)));  
很有趣吧?我们初始的Observable返回的是字符串,最终的Subscriber收到的却是Integer,当然使用lambda可以进一步简化代码:
Observable.just("Hello, world!")  
    .map(s -> s.hashCode())  
    .subscribe(i -> System.out.println(Integer.toString(i)));  
前面说过,Subscriber做的事情越少越好,我们再增加一个map操作符
Observable.just("Hello, world!")  
    .map(s -> s.hashCode())  
    .map(i -> Integer.toString(i))  
    .subscribe(s -> System.out.println(s)); 

》1.Observable和Subscriber可以做任何事情
Observable可以是一个数据库查询,Subscriber用来显示查询结果;Observable可以是屏幕上的点击事件,Subscriber用来响应点击事件;Observable可以是一个网络请求,Subscriber用来显示请求结果。
2.Observable和Subscriber是独立于中间的变换过程的。
在Observable和Subscriber中间可以增减任何数量的map。整个系统是高度可组合的,操作数据是一个很简单的过程。
 EventBus的作用是发布/订阅事件总线
Github:https://github.com/wangjiegulu/RxAndroidEventsSample

EventBus的作用是发布/订阅事件总线,因为项目中用到RxJava、RxAndroid,所以完全可以使用RxJava、RxAndroid来实现EventBus。

1. 编写RxBus,用于存储所有事件Subjects。

事件是传递的最小单位,可以把任何类作为一个事件。

RxBus代码如下:

复制代码
 1 /** 2  * Author: wangjie 3  * Email: tiantian.china.2@gmail.com 4  * Date: 6/11/15. 5  */ 6 public class RxBus { 7     private static final String TAG = RxBus.class.getSimpleName(); 8     private static RxBus instance; 9     public static boolean DEBUG = false;10 11     public static synchronized RxBus get() {12         if (null == instance) {13             instance = new RxBus();14         }15         return instance;16     }17 18     private RxBus() {19     }20 21     private ConcurrentHashMap<Object, List<Subject>> subjectMapper = new ConcurrentHashMap<>();22 23     @SuppressWarnings("unchecked")24     public <T> Observable<T> register(@NonNull Object tag, @NonNull Class<T> clazz) {25         List<Subject> subjectList = subjectMapper.get(tag);26         if (null == subjectList) {27             subjectList = new ArrayList<>();28             subjectMapper.put(tag, subjectList);29         }30 31         Subject<T, T> subject;32         subjectList.add(subject = PublishSubject.create());33         if (DEBUG) Log.d(TAG, "[register]subjectMapper: " + subjectMapper);34         return subject;35     }36 37     public void unregister(@NonNull Object tag, @NonNull Observable observable) {38         List<Subject> subjects = subjectMapper.get(tag);39         if (null != subjects) {40             subjects.remove((Subject) observable);41             if (ABTextUtil.isEmpty(subjects)) {42                 subjectMapper.remove(tag);43             }44         }45 46         if (DEBUG) Log.d(TAG, "[unregister]subjectMapper: " + subjectMapper);47     }48 49     public void post(@NonNull Object content) {50         post(content.getClass().getName(), content);51     }52 53     @SuppressWarnings("unchecked")54     public void post(@NonNull Object tag, @NonNull Object content) {55         List<Subject> subjectList = subjectMapper.get(tag);56 57         if (!ABTextUtil.isEmpty(subjectList)) {58             for (Subject subject : subjectList) {59                 subject.onNext(content);60             }61         }62         if (DEBUG) Log.d(TAG, "[send]subjectMapper: " + subjectMapper);63     }64 }
复制代码

如上述代码,RxBus只提供了register、unregister、post三个方法。

这里又加入了一个tag的概念,也可以理解为channel,注册Subject、反注册Subject和post事件的时候都需要这个tag,只有tag一致才能正常接收到事件。

比如有一个事件类HelloEvent,这个事件的作用是接收到后toast一个提示“hello”,如果两个Activity都注册了这个HelloEvent事件,但是没有tag去限制,一旦post了一个helloEvent事件后,两个Activity都会收到这个事件,导致两个Activity都会toast。如果使用tag,post这个HelloEvent的时候可以设置这个tag,只有register时也使用了这个tag才会接收到这个event。

2. 在Present(如Activity的onCreate)中注册一个Observer(以下以发送一个String类型的事件为例)

复制代码
1 Observable<String> addOb = RxBus.get()2                 .register("addFeedTag", String.class);3 4 addOb.observeOn(AndroidSchedulers.mainThread())5                 .subscribe(s -> {6                     // todo: Accept event and process here7                 });
复制代码

如上,注册了一个String类型的事件,事件的tag是“addFeedTag”,用来增加一个Feed。使用RxAndroid在Action1中处理接收到的这个事件。

3. 在任何地方发送一个事件:

RxBus.get().post("addFeedTag", "hello RxBus!");

这里发送了一个tag为“addFeedTag”的String类型的事件。

4. 反注册Observer:

RxBus.get().unregister("addFeedTag", addOb);

注意:这里的Tag都为“addFeedTag”。

 

下面使用注解的方式更简单方便地使用RxBus(嗯-。-这里才是重点)。

首先来看下使用注解后的代码:

1. 注册Observer

这一步可以省略掉。

2. 发送一个事件(这里我们换一个事件:FeedItemClickEvent,我们定义这个事件是用来处理当Feed被点击后的事件)

RxBus.get().post(new FeedItemClickEvent().setPosition(position).setFeed(feed));

3. 接收事件,然后处理

1 @Accept2 public void onPostAccept(Object tag, FeedItemClickEvent event) {3   Logger.d(TAG, "onPostAccept event: " + event);4   Feed feed = event.getFeed();5   // 跳转到feed详情页面...6 }

如上,这里只需要编写一个方法,加上Accept注解,然后在方法中进行事件处理即可。

注意:方法名可以任意

方法参数一:必须为Object类型的tag;

方法参数二,如果这个方法只接收一种事件,则写明具体的事件类型,如上;如果这个方法接收多种事件,则类型需要为Object。

4. 反注册Observer

这一步也可以省略掉。

 

接收多种事件:

 1 @Accept( 2             acceptScheduler = AcceptScheduler.NEW_THREAD, 3             value = { 4                     @AcceptType(tag = ActionEvent.CLOSE, clazz = String.class), 5                     @AcceptType(tag = ActionEvent.BACK, clazz = String.class), 6                     @AcceptType(tag = ActionEvent.EDIT, clazz = String.class), 7                     @AcceptType(tag = ActionEvent.REFRESH, clazz = String.class) 8             } 9     )10     public void onPostAccept(Object tag, Object actionEvent) {11         Logger.d(TAG, "[ActionEvent]onPostAccept action event name: " + actionEvent);12         // todo: Accept event and process here (in new thread)13     }

这里@Accept注解中设置了acceptScheduler为AcceptScheduler.NEW_THREAD,指明方法运行在子线程中.

value中指明了接收的事件类型,这里表示这个方法接收4种类型的事件:CLOSE, BACK, EDIT, REFRESH.

 

注解解释:

@Accept注解

acceptScheduler: 指定被注解的方法运行的Scheduler。

value[]: AcceptType注解数组,用于指定接收事件的tag和class。

@AcceptType注解:

tag: 接收事件的tag
clazz: 接收事件的类型

 

AcceptScheduler:

详情见:rx.schedulers.Schedulers和rx.android.schedulers.AndroidSchedulers

如果设置的是AcceptScheduler.EXECUTOR或AcceptScheduler.HANDLER,则需要在Application中配置Executor和Handler:

 1 /** 2  * Author: wangjie 3  * Email: tiantian.china.2@gmail.com 4  * Date: 6/15/15. 5  */ 6 public class MyApplication extends Application { 7     private Executor acceptExecutor = Executors.newCachedThreadPool(); 8     private Handler handler = new Handler(Looper.getMainLooper()); 9 10     @Override11     public void onCreate() {12         super.onCreate();13         RxBus.DEBUG = true;14 15         DefaultAcceptConfiguration.getInstance().registerAcceptConfiguration(new DefaultAcceptConfiguration.OnDefaultAcceptConfiguration() {16             @Override17             public Executor applyAcceptExecutor() {18                 return acceptExecutor;19             }20 21             @Override22             public Handler applyAcceptHandler() {23                 return handler;24             }25         });26     }27 }

因为需要对Accept和AcceptType注解的解析,所以项目的BaseActivity需要使用AIAppCompatActivity,然后实现parserMethodAnnotations()方法,使用RxBusAnnotationManager对注解进行

参考和转载地址:https://github.com/lzyzsd/Awesome-RxJava
http://blog.csdn.net/lzyzsd/article/details/41833541
0 0
原创粉丝点击