简介
RxJava
RxJava 是一个在 Java VM 上应用可观测的序列来组成异步的、基于事件的程序的库。RxJava 实质上是一个实现异步操作的库。
我的项目地址: https://github.com/ReactiveX/RxJava
XTask
XTask 是一个拓展性极强的 Android 工作执行框架。通过它,你能够自在定义和组合工作来实现你想要的性能,尤其实用于解决简单的业务流程,可灵便增加前置工作或者调整执行程序。
我的项目的地址: https://github.com/xuexiangjys/XTask
背景
XTask 是我基于 RxJava 的设计思维,并结合实际我的项目中应用的教训所发明进去的一个开源我的项目,其目标就是要代替 RxJava 在 Android 中的局部应用场景,晋升开发的体验和可维护性。
置信应用过 RxJava 的人都晓得 RxJava 有很多硬伤,上面我哦简略列举几个:
- RxJava 最后并不是最先在 Android 中应用的,所以它一开始就设计的相当的简单且轻便,一个库经常能达到 3M 左右,绝对于挪动端而已,这还是十分占利用体积的。
- 远远超过百种的操作符也经常让使用者摸不着头脑,稀里糊涂的应用很容易带来一些致命性的问题,例如内存透露等。
- 因为 RxJava 是一个基于事件的程序库,短少一些要害执行工作的日志信息,这就导致出了问题后会很难排查进去。
而 XTask 就是为了可能解决上述问题而被我开源进去的。
应用比照
首先,RxJava 作为一个优良的开源框架这点是毋庸置疑的,XTask 并不是用来代替 RxJava 的,我没有这种能力,同样 google 也没有。
然而在某些小且罕用的场景下,咱们是齐全能够替换掉 RxJava 的应用的。例如如下两种场景:
- 简单串行工作解决
- 简单并发工作解决
上面我就通过两个小例子来给大家出现它们的不同。
简单串行工作
置信咱们在平时的开发过程中肯定会遇到很多简单的业务流程,而这些流程很多都是一环套着一环,须要一步一步走上来才行,两头有任何谬误都将进行执行。
上面我就以 [高仿网红产品] 的案例流程为例,简略解说如何通过 RxJava
和XTask
去实现这一流程。
案例剖析
高仿网红产品的流程
1. 获取产品信息 -> 2. 查问可生产的工厂 -> 3. 分割工厂生产产品 -> 4. 送去市场部门评估售价 -> 5. 产品上市
实体类设计
这里次要波及 3 个实体类: Product、ProductInfo 和 ProductFactory。
/**
* 产品
*/
public class Product {
/**
* 产品信息
*/
private ProductInfo info;
/**
* 产品生产地址
*/
private String address;
/**
* 产品价格
*/
private String price;
/**
* 产品公布工夫
*/
private String publicTime;
}
/**
* 产品信息
*/
public class ProductInfo {
/**
* 编号
*/
private String id;
/**
* 品牌
*/
private String brand;
/**
* 品质
*/
private String quality;
}
/**
* 产品工厂
*/
public class ProductFactory {
/**
* 工厂 id
*/
private String id;
/**
* 工厂地址
*/
private String address;
}
案例实现
业务流程解决
上述共有 5 个业务流程,咱们将其简化分为以下 4 个处理器进行解决。
- 1. 获取产品信息: GetProductInfoProcessor (productId -> ProductInfo)
- 2. 查找相干的工厂: SearchFactoryProcessor (ProductInfo -> ProductFactory)
- 3. 评估产品,给出价格: GivePriceProcessor (Product -> Product)
- 4. 产品公布: PublicProductProcessor (Product -> Product)
业务流程串联
- 一般写法
一般写法咱们间接应用接口回调的形式, 一层层执行。
AppExecutors.get().singleIO().execute(() -> {
// 1. 获取产品信息
new GetProductInfoProcessor(logger, productId).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<ProductInfo>() {
@Override
public void onSuccess(final ProductInfo productInfo) {
// 2. 查问可生产的工厂
new SearchFactoryProcessor(logger, productInfo).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<ProductFactory>() {
@Override
public void onSuccess(final ProductFactory factory) {
// 3. 分割工厂生产产品
log("开始生产产品...");
Product product = factory.produce(productInfo);
// 4. 送去市场部门评估售价
new GivePriceProcessor(logger, product).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<Product>() {
@Override
public void onSuccess(Product product) {
// 5. 产品上市
PublicProductProcessor publicProductProcessor = new PublicProductProcessor(logger, product);
publicProductProcessor.setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<Product>() {
@Override
public void onSuccess(Product product) {log("总共耗时:" + (System.currentTimeMillis() - startTime) + "ms");
log("仿冒生产网红产品实现," + product);
}
}).process();}
}).process();}
}).process();}
}).process();});
- RxJava 写法
RxJava 中执行串行工作,个别应用 map
或者 flatMap
,这里因为是一对一,所以应用map
执行即可。
disposable = Observable.just(productId)
// 1. 获取产品信息
.map(id -> new GetProductInfoProcessor(logger, id).process())
// 2. 查问可生产的工厂
.map(productInfo -> new Pair<>(new SearchFactoryProcessor(logger, productInfo).process(), productInfo))
.map(productPair -> {
// 3. 分割工厂生产产品
log("开始生产产品...");
Product product = productPair.first.produce(productPair.second);
// 4. 送去市场部门评估售价
return new GivePriceProcessor(logger, product).process();})
// 5. 产品上市
.map(product -> new PublicProductProcessor(logger, product).process())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(product -> {log("总共耗时:" + (System.currentTimeMillis() - startTime) + "ms");
log("仿冒生产网红产品实现," + product);
});
- XTask 写法
与一般写法和 RxJava 写法不同的是,XTask 是把所有的业务处理器都封装在了一个一个的 Task 中,而后按工作的执行程序顺次增加对应的 Task 即可实现。
XTask.getTaskChain()
.setTaskParam(TaskParam.get(ProductTaskConstants.KEY_PRODUCT_ID, productId))
// 1. 获取产品信息
.addTask(new GetProductInfoTask(logger))
// 2. 查问可生产的工厂, 3. 分割工厂生产产品
.addTask(new SearchFactoryTask(logger))
// 4. 送去市场部门评估售价
.addTask(new GivePriceTask(logger))
// 5. 产品上市
.addTask(new PublicProductTask(logger))
.setTaskChainCallback(new TaskChainCallbackAdapter() {
@Override
public void onTaskChainCompleted(@NonNull ITaskChainEngine engine, @NonNull ITaskResult result) {log("总共耗时:" + (System.currentTimeMillis() - startTime) + "ms");
Product product = result.getDataStore().getObject(ProductTaskConstants.KEY_PRODUCT, Product.class);
log("仿冒生产网红产品实现," + product);
}
}).start();
案例执行后果
- 程序执行后果
- XTask 执行日志一览
简单并行任务
除了下面咱们探讨到的常见串行工作,咱们在平时的开发过程中也会遇到一些简单的并行流程。这些流程往往是独自可执行的,虽说前后关联不大,然而又是同时为了某个指标去执行的流程。
上面我就以常见的 [展现商品详细信息] 的案例流程为例,简略解说如何通过 RxJava
和XTask
去实现这一流程。
案例剖析
展现商品详细信息的流程
- 1. 依据商品的惟一号 ID 获取商品简要信息
-
2. 获取商品的详细信息:
- 2.1 获取商品的生产信息
- 2.2 获取商品的价格信息
- 2.3 获取商品的促销信息
- 2.4 获取商品的富文本信息
- 3. 进行商品信息的展现
其中步骤 2 中的 4 个子步骤是能够同时进行,互不影响的并发流程。
实体类设计
这里次要波及 6 个实体类: BriefInfo、Product、FactoryInfo、PriceInfo、PromotionInfo 和 RichInfo。
/**
* 产品简要信息
*/
public class BriefInfo {
private String id;
protected String name;
private String factoryId;
private String priceId;
private String promotionId;
private String richId;
}
/**
* 产品
*/
public class Product extends BriefInfo {
/**
* 生产信息
*/
private FactoryInfo factory;
/**
* 价格信息
*/
private PriceInfo price;
/**
* 促销信息
*/
private PromotionInfo promotion;
/**
* 富文本信息
*/
private RichInfo rich;
}
/**
* 工厂生产信息
*/
public class FactoryInfo {
private String id;
/**
* 生产地址
*/
private String address;
/**
* 生产日期
*/
private String productDate;
/**
* 过期日期
*/
private String expirationDate;
}
/**
* 价格信息
*/
public class PriceInfo {
private String id;
/**
* 出厂价
*/
private float factoryPrice;
/**
* 批发价
*/
private float wholesalePrice;
/**
* 零售价
*/
private float retailPrice;
}
/**
* 产品促销信息
*/
public class PromotionInfo {
private String id;
/**
* 促销类型
*/
private int type;
/**
* 促销内容
*/
private String content;
/**
* 失效日期
*/
private String effectiveDate;
/**
* 生效日期
*/
private String expirationDate;
}
/**
* 富文本信息
*/
public class RichInfo {
private String id;
/**
* 形容信息
*/
private String description;
/**
* 图片链接
*/
private String imgUrl;
/**
* 视频链接
*/
private String videoUrl;
}
案例实现
业务流程解决
上述共有 3 个大业务流程,4 个子业务流程,咱们将其简化分为以下 5 个处理器进行解决。
- 1. 获取商品简要信息: GetBriefInfoProcessor (productId -> BriefInfo)
- 2. 获取商品的生产信息: GetFactoryInfoProcessor (factoryId -> FactoryInfo)
- 3. 获取商品的价格信息: GetPriceInfoProcessor (priceId -> PriceInfo)
- 4. 获取商品的促销信息: GetPromotionInfoProcessor (promotionId -> PromotionInfo)
- 5. 获取商品的富文本信息: GetRichInfoProcessor (richId -> RichInfo)
业务流程串联
- 一般写法
一般写法咱们须要通过接口回调 + 同步锁的形式, 实现工作的并发和协同。
AppExecutors.get().singleIO().execute(() -> {new GetBriefInfoProcessor(logger, productId).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<BriefInfo>() {
@Override
public void onSuccess(BriefInfo briefInfo) {final Product product = new Product(briefInfo);
CountDownLatch latch = new CountDownLatch(4);
// 2.1 获取商品的生产信息
AppExecutors.get().networkIO().execute(() -> {new GetFactoryInfoProcessor(logger, product.getFactoryId()).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<FactoryInfo>() {
@Override
public void onSuccess(FactoryInfo result) {product.setFactory(result);
latch.countDown();}
}).process();});
// 2.2 获取商品的价格信息
AppExecutors.get().networkIO().execute(() -> {new GetPriceInfoProcessor(logger, product.getPriceId()).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<PriceInfo>() {
@Override
public void onSuccess(PriceInfo result) {product.setPrice(result);
latch.countDown();}
}).process();});
// 2.3 获取商品的促销信息
AppExecutors.get().networkIO().execute(() -> {new GetPromotionInfoProcessor(logger, product.getPromotionId()).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<PromotionInfo>() {
@Override
public void onSuccess(PromotionInfo result) {product.setPromotion(result);
latch.countDown();}
}).process();});
// 2.4 获取商品的富文本信息
AppExecutors.get().networkIO().execute(() -> {new GetRichInfoProcessor(logger, product.getRichId()).setProcessorCallback(new AbstractProcessor.ProcessorCallbackAdapter<RichInfo>() {
@Override
public void onSuccess(RichInfo result) {product.setRich(result);
latch.countDown();}
}).process();});
try {latch.await();
log("总共耗时:" + (System.currentTimeMillis() - startTime) + "ms");
log("查问商品信息实现," + product);
} catch (InterruptedException e) {e.printStackTrace();
}
}
}).process();});
- RxJava 写法
RxJava 中执行并行任务,个别应用 merge
或者 zip
,这里因为须要协同,所以应用zip
对工作流进行合并。
disposable = Observable.just(productId)
// 1. 获取商品简要信息
.map(id -> new GetBriefInfoProcessor(logger, id).process())
.map(Product::new)
.flatMap(product ->
Observable.zip(
// 2.1 获取商品的生产信息
Observable.fromCallable(() -> new GetFactoryInfoProcessor(logger, product.getFactoryId()).process()).subscribeOn(Schedulers.io()),
// 2.2 获取商品的价格信息
Observable.fromCallable(() -> new GetPriceInfoProcessor(logger, product.getPriceId()).process()).subscribeOn(Schedulers.io()),
// 2.3 获取商品的促销信息
Observable.fromCallable(() -> new GetPromotionInfoProcessor(logger, product.getPromotionId()).process()).subscribeOn(Schedulers.io()),
// 2.4 获取商品的富文本信息
Observable.fromCallable(() -> new GetRichInfoProcessor(logger, product.getRichId()).process()).subscribeOn(Schedulers.io()), (factoryInfo, priceInfo, promotionInfo, richInfo) -> product.setFactory(factoryInfo)
.setPrice(priceInfo)
.setPromotion(promotionInfo)
.setRich(richInfo)
)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(product -> {log("总共耗时:" + (System.currentTimeMillis() - startTime) + "ms");
log("查问商品信息实现," + product);
});
- XTask 写法
XTask 是把所有的业务处理器都封装在了一个一个的 Task 中,而后并行的工作须要通过一个 ConcurrentGroupTask(同步组工作)进行包裹,其余按失常执行程序增加 Task 即可。
XTask.getTaskChain()
.setTaskParam(TaskParam.get(ProductTaskConstants.KEY_PRODUCT_ID, productId))
// 1. 获取商品简要信息
.addTask(new GetBriefInfoTask(logger))
.addTask(XTask.getConcurrentGroupTask(ThreadType.SYNC)
// 2.1 获取商品的生产信息
.addTask(new GetFactoryInfoTask(logger))
// 2.2 获取商品的价格信息
.addTask(new GetPriceInfoTask(logger))
// 2.3 获取商品的促销信息
.addTask(new GetPromotionInfoTask(logger))
// 2.4 获取商品的富文本信息
.addTask(new GetRichInfoTask(logger)))
.setTaskChainCallback(new TaskChainCallbackAdapter() {
@Override
public void onTaskChainCompleted(@NonNull ITaskChainEngine engine, @NonNull ITaskResult result) {log("总共耗时:" + (System.currentTimeMillis() - startTime) + "ms");
Product product = result.getDataStore().getObject(ProductTaskConstants.KEY_PRODUCT, Product.class);
log("查问商品信息实现," + product);
}
}).start();
案例执行后果
- 程序执行后果
- XTask 执行日志一览
应用比照总结
从下面的应用比照来看,咱们能够简略演绎总结以下几点:
编程形式
1.RxJava 遵循的是函数响应式编程的准则,处理过程都是基于数据流的解决。这样的益处就是,咱们能够最直观无效的感触到数据的变动过程,当然毛病就是太过于细化和具体,不合乎面向对象的设计模式准则,减少了日后的代码保护老本。当然如果数据的构造绝对稳固的话,这样的编程形式还能够承受,但如果数据或者业务频繁产生变动的话,这样的编程形式几乎就是天堂。
2.XTask 遵循的是面向对象的编程准则,每个处理过程都对应了一个具体或者形象的 Task。这样的益处就是,缩小了业务和数据结构之间的耦合,同时也缩小了各个业务之间的耦合。这样即便你的数据结构或者业务流程呈现大的变动,性能实现的主体也不会产生大的改变,更多的只是每个子业务 Task 外部的改变和调整,真正实现了高复用低耦合。
总结: 两种不同的编程形式,遵循两种不同的编程准则,无奈进行比照。
上手难度
如果你是一名 RxJava 的开发老鸟的话,这样就没什么可比性了,这里我只是从初学者的角度来说。
1.RxJava 领有宏大简单的操作符,上百种操作符肯定会让初学者摸不着头脑,如果在不相熟的状况下强行应用,很容易导致误用而产生很多意想不到的问题(比方内存透露或者 OOM 等)。
2.XTask 作为专为 Android 设计的工作执行框架,性能绝对繁多。没有简单的操作符,有的只是“工作链、工作、组工作、工作参数和执行后果”这五个组成因素,应用起来绝对简略容易上手。
总结: 整体比拟下来,XTask 要优于 RxJava。
开发效率
1.RxJava 的开发效率次要取决于开发者对 RxJava 操作符应用的熟练程度。越是可能纯熟应用操作符,开发效率就越高,出问题的概率也越小。
2.XTask 相对而言就平滑了许多,开发效率和应用的熟练程度关系不大(次要还是上手难度不高)。然而因为每个业务子步骤都须要写一个 Task 类,对于那些应用 RxJava 比拟纯熟的人而言,效率是显著会低一些。
总结: 整体比拟下来,从长期而言,RxJava 要优于 XTask。
可维护性
1.RxJava 遵循的是函数响应式编程的准则,实质上还是面向过程式的编程。所有的业务流程都和数据有着比拟强的耦合,当数据结构或者业务流程产生变动的时候,必然会影响到骨干代码的变动。而且对于初入我的项目的开发人员接手我的项目的时候,能看到的往往是部分业务数据流的变动,无奈从全局的视角去了解我的项目主体业务,很容易产生部分批改影响全局的后果。
2.XTask 遵循的是面向对象的编程准则,设计之初就严格遵循面向对象的设计模式准则。充沛缩小业务与业务、业务与数据流之间的耦合,这样即便你的数据结构或者业务流程呈现重大的变动,骨干代码也不会有很大的变动。而且 XTask 领有较强的日志记录零碎,可能十分清晰的记录你当前任务链的执行过程和所在线程的信息(主动的),当工作执行呈现问题的时候,便能很快地定位出问题产生的地位。而对于初入我的项目的开发人员来说,也能疾速从工作执行过程的日志中去了解我的项目的主体业务。待主体业务流程有了分明的认知后再去认真看子业务,这样能力全方位了解我的项目的业务,也更利于我的项目的保护。
总结: 整体比拟下来,XTask 完胜 RxJava。
性能
在性能上,XTask 为了实现业务与数据之间的隔离,设计了共享数据的构造,相比拟 RxJava 而言,多了数据拷贝以及数据存储的过程,所以无论是在工夫还是空间上而言,RxJava 都是较优于 XTask 的。
最初
综合以上的阐述,XTask 和 RxJava 各有各的劣势。正如我文章结尾所说: XTask 并不是用来代替 RxJava 的。XTask 只是作为 RxJava 在 Android 工作执行流程上的一种补充,喜爱的敌人能够关注 XTask 的我的项目主页: https://github.com/xuexiangjys/XTask。
我是 xuexiangjys,一枚酷爱学习,喜好编程,致力于 Android 架构钻研以及开源我的项目教训分享的技术 up 主。获取更多资讯,欢送微信搜寻公众号:【我的 Android 开源之旅】