Transformer 在RxJava中的使用

简介: Transformer 在RxJava中的使用

Transformer 用途



Transformer,顾名思义是转换器的意思。早在 RxJava1.x 版本就有了Observable.Transformer、Single.Transformer和Completable.Transformer,在2.x版本中变成了ObservableTransformer、SingleTransformer、CompletableTransformer、FlowableTransformer和MaybeTransformer。其中,FlowableTransformer和MaybeTransformer是新增的。由于 RxJava2 将Observable拆分成 Observable 和 Flowable,所以多了一个FlowableTransformer。同时,Maybe是 RxJava2 新增的一个类型,所以多了MaybeTransformer。


Transformer 能够将一个 Observable/Flowable/Single/Completable/Maybe 对象转换成另一个 Observable/Flowable/Single/Completable/Maybe 对象,和调用一系列的内联操作符是一模一样的。


举个简单的例子,写一个transformer()方法将一个发射整数的Observable转换为发射字符串的Observable。

public static <String> ObservableTransformer<Integer, java.lang.String> transformer() {
        return new ObservableTransformer<Integer, java.lang.String>() {
            @Override
            public ObservableSource<java.lang.String> apply(@NonNull Observable<Integer> upstream) {
                return upstream.map(new Function<Integer, java.lang.String>() {
                    @Override
                    public java.lang.String apply(@NonNull Integer integer) throws Exception {
                        return java.lang.String.valueOf(integer);
                    }
                });
            }
        };
    }


接下来是使用transformer()方法,通过标准的RxJava的操作。

Observable.just(123,456)
       .compose(transformer())
       .subscribe(new Consumer<String>() {
              @Override
               public void accept(@io.reactivex.annotations.NonNull String s) throws Exception {
                   System.out.println("s="+s);
                    }
                });


最后打印了二次,分别是

s=123
s=456


通过这个例子,可以简单和直观地了解到Transformer的作用。


其实,在大名鼎鼎的图片加载框架 Glide 以及 Picasso 中也有类似的transform概念,能够将图形进行变换。


跟compose操作符相结合



compose操作于整个数据流中,能够从数据流中得到原始的Observable<T>/Flowable<T>...


当创建Observable/Flowable...时,compose操作符会立即执行,而不像其他的操作符需要在onNext()调用后才执行。


关于compose操作符,老外的这篇文章不错Don't break the chain: use RxJava's compose() operator


国内也有相应的翻译【译】避免打断链式结构:使用.compose( )操作符


常用的场景



1. 切换到主线程


对于网络请求,我们经常会做如下的操作来切换线程。


.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())


于是,我做了一个简单的封装。

import io.reactivex.FlowableTransformer
import io.reactivex.ObservableTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
/**
 * Created by Tony Shen on 2017/7/13.
 */
object RxJavaUtils {
    @JvmStatic
    fun <T> observableToMain():ObservableTransformer<T, T> {
        return ObservableTransformer{
            upstream ->
            upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
        }
    }
    @JvmStatic
    fun <T> flowableToMain(): FlowableTransformer<T, T> {
        return FlowableTransformer{
            upstream ->
            upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
        }
    }
}


上面这段代码是Kotlin写的,为啥不用Java?个人习惯把一些工具类来用Kotlin来编写,而且使用lambda表达式也更为直观。


对于Flowable切换到主线程的操作,可以这样使用

.compose(RxJavaUtils.flowableToMain())


2. RxLifecycle中的LifecycleTransformer


trello出品的RxLifecycle能够配合Android的生命周期,防止App内存泄漏,其中就使用了LifecycleTransformer。


知乎也做了一个类似的RxLifecycle,能够做同样的事情。


在我的项目中也使用了知乎的RxLifecycle,根据个人的习惯和爱好,我对LifecycleTransformer稍微做了一些修改,将五个Transformer合并成了一个。

import org.reactivestreams.Publisher;
import io.reactivex.Completable;
import io.reactivex.CompletableSource;
import io.reactivex.CompletableTransformer;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.MaybeTransformer;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.SingleTransformer;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.processors.BehaviorProcessor;
/**
 * Created by Tony Shen on 2017/5/25.
 */
public class LifecycleTransformer<T> implements ObservableTransformer<T, T>,
        FlowableTransformer<T, T>,
        SingleTransformer<T, T>,
        MaybeTransformer<T, T>,
        CompletableTransformer {
    private final BehaviorProcessor<Integer> lifecycleBehavior;
    private LifecycleTransformer() throws IllegalAccessException {
        throw new IllegalAccessException();
    }
    public LifecycleTransformer(@NonNull BehaviorProcessor<Integer> lifecycleBehavior) {
        this.lifecycleBehavior = lifecycleBehavior;
    }
    @Override
    public CompletableSource apply(Completable upstream) {
        return upstream.ambWith(
                lifecycleBehavior.filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(@LifecyclePublisher.Event Integer event) throws Exception {
                        return event == LifecyclePublisher.ON_DESTROY_VIEW ||
                                event == LifecyclePublisher.ON_DESTROY ||
                                event == LifecyclePublisher.ON_DETACH;
                    }
                }).take(1).flatMapCompletable(new Function<Integer, Completable>() {
                    @Override
                    public Completable apply(Integer flowable) throws Exception {
                        return Completable.complete();
                    }
                })
        );
    }
    @Override
    public Publisher<T> apply(final Flowable<T> upstream) {
        return upstream.takeUntil(
                lifecycleBehavior.skipWhile(new Predicate<Integer>() {
                    @Override
                    public boolean test(@LifecyclePublisher.Event Integer event) throws Exception {
                        return event != LifecyclePublisher.ON_DESTROY_VIEW &&
                                event != LifecyclePublisher.ON_DESTROY &&
                                event != LifecyclePublisher.ON_DETACH;
                    }
                })
        );
    }
    @Override
    public MaybeSource<T> apply(Maybe<T> upstream) {
        return upstream.takeUntil(
                lifecycleBehavior.skipWhile(new Predicate<Integer>() {
                    @Override
                    public boolean test(@LifecyclePublisher.Event Integer event) throws Exception {
                        return event != LifecyclePublisher.ON_DESTROY_VIEW &&
                                event != LifecyclePublisher.ON_DESTROY &&
                                event != LifecyclePublisher.ON_DETACH;
                    }
                })
        );
    }
    @Override
    public ObservableSource<T> apply(Observable<T> upstream) {
        return upstream.takeUntil(
                lifecycleBehavior.skipWhile(new Predicate<Integer>() {
                    @Override
                    public boolean test(@LifecyclePublisher.Event Integer event) throws Exception {
                        return event != LifecyclePublisher.ON_DESTROY_VIEW &&
                                event != LifecyclePublisher.ON_DESTROY &&
                                event != LifecyclePublisher.ON_DETACH;
                    }
                }).toObservable()
        );
    }
    @Override
    public SingleSource<T> apply(Single<T> upstream) {
        return upstream.takeUntil(
                lifecycleBehavior.skipWhile(new Predicate<Integer>() {
                    @Override
                    public boolean test(@LifecyclePublisher.Event Integer event) throws Exception {
                        return event != LifecyclePublisher.ON_DESTROY_VIEW &&
                                event != LifecyclePublisher.ON_DESTROY &&
                                event != LifecyclePublisher.ON_DETACH;
                    }
                })
        );
    }
}


3. 缓存的使用


对于缓存,我们大致都会这样写

cache.put(key,value);


更优雅一点的做法是使用AOP,大致会这样写

@Cacheable(key = "...")
getValue() {
    ....
}


如果你想在RxJava的链式调用中也使用缓存,还可以考虑使用transformer的方式,下面我写了一个简单的方法

/**
 * Created by Tony Shen on 2017/7/13.
 */
public class RxCache {
    public static <T> FlowableTransformer<T, T> transformer(final String key, final Cache cache) {
        return new FlowableTransformer<T, T>() {
            @Override
            public Publisher<T> apply(@NonNull Flowable<T> upstream) {
                return upstream.map(new Function<T, T>() {
                    @Override
                    public T apply(@NonNull T t) throws Exception {
                        cache.put(key,(Serializable) t);
                        return t;
                    }
                });
            }
        };
    }
}


结合上述三种使用场景,封装了一个方法用于获取内容,在这里网络框架使用Retrofit。虽然Retrofit本身支持通过Interceptor的方式来添加Cache,但是可能某些业务场景下还是想用自己的Cache,那么可以采用下面类似的封装。

/**
     * 获取内容
     * @param fragment
     * @param param
     * @param cacheKey
     * @return
     */
    public Flowable<ContentModel> getContent(Fragment fragment,ContentParam param,String cacheKey) {
        return apiService.loadVideoContent(param)
                .compose(RxLifecycle.bind(fragment).<ContentModel>toLifecycleTransformer())
                .compose(RxJavaUtils.<ContentModel>flowableToMain())
                .compose(RxCache.<ContentModel>transformer(cacheKey,App.getInstance().cache));
    }


4. 追踪RxJava的使用


初学者可能会对RxJava内部的数据流向会感到困惑,所以我写了一个类用于追踪RxJava的使用,对于调试代码还蛮有帮助的。


先来看一个简单的例子

Observable.just("tony","cafei","aaron")
                .compose(RxTrace.<String>logObservable("first",RxTrace.LOG_SUBSCRIBE|RxTrace.LOG_NEXT_DATA))
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@io.reactivex.annotations.NonNull String s) throws Exception {
                        System.out.println("s="+s);
                    }
                });


下图显示了上面代码中的数据流向。


image.png

第一次做Trace.png


然后,再刚才代码的基础上加一个map操作符,把小写的字符串都转换成大写。

Observable.just("tony","cafei","aaron")
                .compose(RxTrace.<String>logObservable("first",RxTrace.LOG_SUBSCRIBE|RxTrace.LOG_NEXT_DATA))
                .map(new Function<String, String>() {
                    @Override
                    public String apply(@io.reactivex.annotations.NonNull String s) throws
                            Exception {
                        return s.toUpperCase();
                    }
                })
                .compose(RxTrace.<String>logObservable("second",RxTrace.LOG_NEXT_DATA))
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@io.reactivex.annotations.NonNull String s) throws Exception {
                        System.out.println("s="+s);
                    }
                });

看看这一次数据是怎样流向的,由于显示器不够大,其实截图还少了一点内容:(,但是能够看明白日志的展示。


image.png

第二次做Trace.png


最后,加上监测onComlete和OnTerminate

Observable.just("tony","cafei","aaron")
                .compose(RxTrace.<String>logObservable("first",RxTrace.LOG_SUBSCRIBE|RxTrace.LOG_NEXT_DATA))
                .map(new Function<String, String>() {
                    @Override
                    public String apply(@io.reactivex.annotations.NonNull String s) throws
                            Exception {
                        return s.toUpperCase();
                    }
                })
                .compose(RxTrace.<String>logObservable("second",RxTrace.LOG_NEXT_DATA))
                .compose(RxJavaUtils.<String>observableToMain())
                .compose(RxTrace.<String>logObservable("third",RxTrace.LOG_COMPLETE|RxTrace.LOG_TERMINATE))
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@io.reactivex.annotations.NonNull String s) throws Exception {
                        System.out.println("s="+s);
                    }
                });


上面已经展示过的截图就不显示了,就展示最后的onComlete和OnTerminate。


image.png

第三次做Trace.png


最后,我已经把RxTrace的代码放到https://github.com/fengzhizi715/SAF-Kotlin-log

为何不单独开一个repository呢?它只有一个类,我就懒得创建了:(


总结



compose操作符和Transformer结合使用,一方面让代码看起来更加简洁化,另一方面能够提高代码的复用性。RxJava提倡链式调用,compose能够防止链式被打破。

相关文章
|
3月前
|
网络协议 前端开发 JavaScript
HTTP协议初认识、速了解
系统讲解HTTP定义、特点(无状态、无连接、灵活等)、版本演进(HTTP/1.0→1.1→2.0对比),以及URI/URL/URN区别和请求流程,适合初学者快速掌握核心概念。
2425 0
HTTP协议初认识、速了解
|
3月前
|
人工智能 安全 测试技术
AI红队测试是什么:转岗大模型评测的最短路径
本文详解AI红队测试——面向大模型与Agent的安全评测新方向。结合欧盟AI法案落地、前沿安全风险(如Prompt注入、越权调用)及企业工程需求,阐明其非传统渗透测试,而是覆盖对抗诱导、边界守卫与可控性验证的系统性质量工程。为测试工程师提供从自动化能力迁移至AI安全评测的清晰进阶路径。
|
3月前
|
缓存 文字识别 安全
【第二部分:大模型应用开发基础】6. Prompt Engineering 与 Context Engineering:生产级 Agent 如何管理上下文
本文从 Agent 开发实践出发,分析 Prompt Engineering 的作用与边界,说明复杂 Agent 为什么不能依赖超长 Prompt,并系统介绍 Context Engineering 对系统指令、用户目标、业务数据、工具结果、历史消息和任务状态的动态选择、组装、裁剪与压缩。文章结合合同审查 Agent 与 Java 示例,进一步讨论 Context Rot、Token 预算、Prompt Cache、可观测性及 Prompt Injection 防护,帮助开发者建立生产级 Agent 的上下文管理思路。
301 1
|
4月前
|
数据采集 供应链 监控
1688评论接口:B2B电商自动化运营与数据风控的核心抓手
1688官方评论接口(alibaba.trade.rate.get)是合规、结构化获取B2B商品评价的唯一标准通道,支持批量、时序化拉取评分、SKU评价、追评等核心字段,赋能货源风控、智能选品、竞品分析、舆情监控与产品迭代,助力电商系统实现数据驱动自动化运营。
394 1
|
11月前
|
NoSQL 前端开发 BI
MongoDB 分页、排序与统计查询技巧
MongoDB 提供 `count()`、`sort()`、`skip()`、`limit()` 等链式方法,高效实现数据统计、分页与排序。支持多字段排序、条件分页,执行顺序固定为:先排序 → 再跳过 → 后限制数量,适用于各类业务场景的数据查询处理。(239字符)
|
8月前
|
测试技术 Go 芯片
2A单节锂电池充电芯片PW4213的IC测试应用
PW4213是一款专为单节锂电池(3.7V/4.2V)设计的同步降压型充电管理IC。与常见的5V输入充电芯片不同,PW4213支持宽电压输入(4.5V-15V),可直接使用5V-12V适配器为单节锂电池充电,内部集成同步降压架构,在大压差应用下效率高、发热低。 工作模式:降压(Buck)拓扑,将5V/9V/12V输入降压至4.2V给单节锂电池充电 开关频率:500kHz,可使用小型化电感电容 最大充电电流:2A,可通过外接检流电阻调节 封装形式:SOP8-EP(底部带散热焊盘)
|
11月前
|
人工智能 边缘计算 自然语言处理
魔珐星云:免费体验企业级3D AI数字人智能客服!告别枯燥对话框!
魔珐科技携手魔搭社区上线「魔珐星云智能客服Demo」,基于超写实3D数字人技术,打造具身智能交互新体验。通过文生多模态3D大模型,实现语音、表情、动作实时生成,支持Web端低延时互动,百元级芯片即可运行,助力企业构建自然高效的人机对话系统。
1189 4
魔珐星云:免费体验企业级3D AI数字人智能客服!告别枯燥对话框!
|
10月前
|
人工智能 自然语言处理 搜索推荐
Geo优化:让联系方式在AI搜索中“被看见”的SOP
Geo专家于磊老师首创的“两大核心+四轮驱动”Geo优化体系,为企业提供了一个系统化、规范化、高效化的增长路径。
461 0
|
11月前
|
运维 监控 Devops
Linux 开发进阶:从初级运维到 DevOps 工程师的能力提升路径
在云计算时代,Linux运维正迈向自动化与智能化。本文梳理从初级运维到DevOps工程师的三阶跃迁路径:先掌握Shell脚本与Ansible实现自动化;再学习Docker容器化技术,构建高可用架构;最终落地CI/CD流水线与全链路监控,打通开发与运维壁垒。通过实战案例详解LNMP环境的DevOps改造,助力运维人员系统提升效率,实现能力突破。(238字)
568 0
|
存储 负载均衡 数据中心
聚合网卡和Wondershaper限速的一些问题(速度减半问题)
聚合网卡,又称为链路聚合组(LAG, Link Aggregation Group)、端口汇聚(Port Trunking)、以太通道(Ethernet Bonding)等,是一种网络技术,通过将两个或多个物理以太网接口(网卡)逻辑上捆绑在一起,形成一个单一的虚拟接口。这种技术不仅提升了网络连接的可用性和带宽,同时也增强了网络的稳定性和可靠性。以下是聚合网卡的一些关键概念、工作原理以及其优势:
818 2

热门文章

最新文章