RxJava 自定义操作符(实现自己的操作符)
2016-07-29 09:30
267 查看
你可以实现你自己的Observable操作符,本文展示怎么做。
如果你的操作符是被用于创造一个Observable,而不是变换或者响应一个Observable,使用 create( ) 方法,不要试图手动实现 Observable。另外,你可以按照下面的用法说明创建一个自定义的操作符。
如果你的操作符是用于Observable发射的单独的数据项,按照下面的说明做:Sequence Operators 。如果你的操作符是用于变换Observable发射的整个数据序列,按照这个说明做:Transformational Operators 。
下面这部分向你展示了你的操作符的脚手架形式,以便它能正确的与lift()搭配使用。
下面这部分向你展示了你的操作符的脚手架形式,以便它能正确的与compose()搭配使用。
请注意:你的序列操作符必须复合Observable协议的核心原则:
它可能调用订阅者的 onNext( ) 方法任意次,但是这些调用必须是不重叠的。
它只能调用订阅者的 onCompleted( ) 或 onError( ) 正好一次,但不能都调用,而且不能在这之后调用订阅者的 onNext( ) 方法。
如果你不能保证你得操作符遵从这两个原则,你可以给它添加 serialize( ) 操作符,它会强制保持正确的行为。
请关注这里 Issue #1962 —需要有一个计划创建一个测试脚手架,你可以用它来写测试验证你的新操作符遵从了Observable协议。
不要让你的操作符阻塞别的操作。
When possible, you should compose new operators by combining existing operators, rather than implementing them with new code. RxJava itself does this with some of its standard operators, for example:
如果可能,你应该组合现有的操作符创建你的新操作符,而不是从零开始实现它。 - RxJava自身的标准操作符也是这样做的,例如:
first( ) 被定义为 take(1).single( )
ignoreElements( ) 被定义为 filter(alwaysFalse( ))
reduce(a) 被定义为 scan(a).last( )
如果你的操作符使用了函数或者lambda表达式作为参数,请注意它们可能是异常的来源,而且要准备好捕获这些异常,并且使用 onError() 通知订阅者。
某些异常被认为是致命的,对它们来说,调用 onError()毫无意义,那样或者是无用的,或者只是对问题的妥协。你可以使用 Exceptions.throwIfFatal(throwable) 方法过滤掉这些致命的异常,并重新抛出它们,而不是试图发射关于它们的通知。
一般说来,一旦发生错误应立即通知订阅者,而不是首先尝试发射更多的数据。
请注意 null 可能是Observable发射的一个合法数据。频繁发生错误的一个来源是:测试一些变量并且将持有一个非 null 值作为是否发射了数据的替代。一个值为 null 的数据仍然是一个发射数据项,它与没有发射任何东西是不能等同的。
想让你的操作符在反压(backpressure)场景中变得得好可能会非常棘手。可以参考Dávid Karnok的博客 Advanced RxJava,这里有一个涉及到的各种因素和怎样处理它们的很值得看的讨论。
本文内容来自:https://github.com/mcxiaoke/RxDocs
如果你的操作符是被用于创造一个Observable,而不是变换或者响应一个Observable,使用 create( ) 方法,不要试图手动实现 Observable。另外,你可以按照下面的用法说明创建一个自定义的操作符。
如果你的操作符是用于Observable发射的单独的数据项,按照下面的说明做:Sequence Operators 。如果你的操作符是用于变换Observable发射的整个数据序列,按照这个说明做:Transformational Operators 。
序列操作符
下面的例子向你展示了怎样使用lift( )操作符将你的自定义操作符(在这个例子中是 myOperator)与标准的RxJava操作符(如ofType和map)一起使用:fooObservable = barObservable.ofType(Integer).map({it*2}).lift(new MyOperator<T>()).map({"transformed by myOperator: " + it});
下面这部分向你展示了你的操作符的脚手架形式,以便它能正确的与lift()搭配使用。
实现你的操作符
将你的自定义操作符定义为实现了 Operator 接口的一个公开类, 就像这样:public class MyOperator<T> implements Operator<T> { public MyOperator( /* any necessary params here */ ) { /* 这里添加必要的初始化代码 */ } @Override public Subscriber<? super T> call(final Subscriber<? super T> s) { return new Subscriber<t>(s) { @Override public void onCompleted() { /* 这里添加你自己的onCompleted行为,或者仅仅传递完成通知: */ if(!s.isUnsubscribed()) { s.onCompleted(); } } @Override public void onError(Throwable t) { /* 这里添加你自己的onError行为, 或者仅仅传递错误通知:*/ if(!s.isUnsubscribed()) { s.onError(t); } } @Override public void onNext(T item) { /* 这个例子对结果的每一项执行排序操作,然后返回这个结果 */ if(!s.isUnsubscribed()) { transformedItem = myOperatorTransformOperation(item); s.onNext(transformedItem); } } }; } }
变换操作符
下面的例子向你展示了怎样使用 compose( ) 操作符将你得自定义操作符(在这个例子中,是一个名叫myTransformer的操作符,它将一个发射整数的Observable转换为发射字符串的)与标准的RxJava操作符(如ofType和map)一起使用:fooObservable = barObservable.ofType(Integer).map({it*2}).compose(new MyTransformer<Integer,String>()).map({"transformed by myOperator: " + it});
下面这部分向你展示了你的操作符的脚手架形式,以便它能正确的与compose()搭配使用。
实现你的变换器
将你的自定义操作符定义为实现了 Transformer 接口的一个公开类,就像这样:public class MyTransformer<Integer,String> implements Transformer<Integer,String> { public MyTransformer( /* any necessary params here */ ) { /* 这里添加必要的初始化代码 */ } @Override public Observable<String> call(Observable<Integer> source) { /* * 这个简单的例子Transformer应用一个map操作, * 这个map操作将发射整数变换为发射整数的字符串表示。 */ return source.map( new Func1<Integer,String>() { @Override public String call(Integer t1) { return String.valueOf(t1); } } ); } }
参见
“Don’t break the chain: use RxJava’s compose() operator” by Dan Lew其它需要考虑的
在发射任何数据(或者通知)给订阅者之前,你的序列操作符可能需要检查它的 Subscriber.isUnsubscribed( ) 状态,如果没有订阅者了,没必要浪费时间生成数据项。请注意:你的序列操作符必须复合Observable协议的核心原则:
它可能调用订阅者的 onNext( ) 方法任意次,但是这些调用必须是不重叠的。
它只能调用订阅者的 onCompleted( ) 或 onError( ) 正好一次,但不能都调用,而且不能在这之后调用订阅者的 onNext( ) 方法。
如果你不能保证你得操作符遵从这两个原则,你可以给它添加 serialize( ) 操作符,它会强制保持正确的行为。
请关注这里 Issue #1962 &mdash;需要有一个计划创建一个测试脚手架,你可以用它来写测试验证你的新操作符遵从了Observable协议。
不要让你的操作符阻塞别的操作。
When possible, you should compose new operators by combining existing operators, rather than implementing them with new code. RxJava itself does this with some of its standard operators, for example:
如果可能,你应该组合现有的操作符创建你的新操作符,而不是从零开始实现它。 - RxJava自身的标准操作符也是这样做的,例如:
first( ) 被定义为 take(1).single( )
ignoreElements( ) 被定义为 filter(alwaysFalse( ))
reduce(a) 被定义为 scan(a).last( )
如果你的操作符使用了函数或者lambda表达式作为参数,请注意它们可能是异常的来源,而且要准备好捕获这些异常,并且使用 onError() 通知订阅者。
某些异常被认为是致命的,对它们来说,调用 onError()毫无意义,那样或者是无用的,或者只是对问题的妥协。你可以使用 Exceptions.throwIfFatal(throwable) 方法过滤掉这些致命的异常,并重新抛出它们,而不是试图发射关于它们的通知。
一般说来,一旦发生错误应立即通知订阅者,而不是首先尝试发射更多的数据。
请注意 null 可能是Observable发射的一个合法数据。频繁发生错误的一个来源是:测试一些变量并且将持有一个非 null 值作为是否发射了数据的替代。一个值为 null 的数据仍然是一个发射数据项,它与没有发射任何东西是不能等同的。
想让你的操作符在反压(backpressure)场景中变得得好可能会非常棘手。可以参考Dávid Karnok的博客 Advanced RxJava,这里有一个涉及到的各种因素和怎样处理它们的很值得看的讨论。
本文内容来自:https://github.com/mcxiaoke/RxDocs
相关文章推荐
- RxJava 自定义操作符(实现自己的操作符)
- (4.6.22.3)来吧,是时候撸一份自己的RxJava框架啦:装饰器模式实现操作符顺序调用
- JQuery实现个性化,可以拖拽 自定义自己的界面(一)
- JQuery实现个性化,可以拖拽 自定义自己的界面(三)
- Android 打造自己的个性化应用(四):仿墨迹天气实现-->自定义扩展名的zip格式的皮肤
- 让驰骋工作流程引擎 ccbpm使用自定义表单来实现自己的业务逻辑.
- 自定义控件实现广告头自动移动,viewpager的运用,和自己利用xml画图,自定义圆点,构造选择器的方法
- 实现=操作符时判断自己给自己赋值
- 自定义ListView item包含checkbox实现单选记录自己开发是遇到的问题
- 自定义autoCompleteTextView实现自己的匹配规则。
- 如何实现artTemplate模板的可重用性,以此框架打造自己的自定义组件
- 最简单自定义实现ArrayAdapter,可以显示自己的逻辑
- JQuery实现个性化,可以拖拽 自定义自己的界面(四)
- Android 打造自己的个性化应用(四):仿墨迹天气实现-->自定义扩展名的zip格式的皮肤
- 采用C#WPF实现自己的网页浏览器(自定义Tab控件)
- Activiti5第七弹,自己实现一个ProcessEngineConfiguration同时自定义拦截器
- JQuery实现个性化,可以拖拽 自定义自己的界面(二)
- 在Android中,可以自定义类,继承ViewGroup等容器类,以实现自己需要的布局显示。
- [C#]简单重写IComparer接口,实现自己的String.CompareTo 方法,自定义比较规则。
- 实现自己自定义的弹框和遮罩层