魔兽世界前传java_RxJava 前传 ①

RxJava 近几年开始在 Android 开发者社区流行,但是由于解决的是复杂的异步操作问题,再加上 Java 语法的限制导致 RxJava 的代码看起来比较费劲,RxJav 的学习曲线也进一步被拉高了。本文介绍 RxJava 的基本原理以及其要解决的问题,来帮助初学者理解 RxJava 框架。

Cat App

将使用一个真实世界的例子来逐步帮助大家理解 RxJava 的设计思想。 所以我们将创建一个下载 Cat 图片的应用。

需要解决的问题是:

有一个 web 服务提供了一些 API 来搜索整个网络上的符合查询关键字的所有猫的图片。 每个图片包含一个可爱程度的参数 – 一个整数值表示其可爱程度。 我们的任务就是 :下载返回的猫图片,选择最可爱的那个,并且把图片保存到本地存储中。

我们只关注 下载、处理和保存图片的三个核心功能。

下面开动吧!

Model 和 API

下面是一个简单的描述 Cat 的模型类:

Java

public class Cat implements Comparable{

Bitmap image;

int cuteness;

@Override

public int compareTo(Cat another) {

return Integer.compare(cuteness, another.cuteness);

}

}

1

2

3

4

5

6

7

8

9

publicclassCatimplementsComparable{

Bitmapimage;

intcuteness;

@Override

publicintcompareTo(Catanother){

returnInteger.compare(cuteness,another.cuteness);

}

}

我们的 API 将会使用来自 cat-sdk.jar 中的阻塞风格的接口。

Java

public interface Api {

List queryCats(String query);

Uri store(Cat cat);

}

1

2

3

4

publicinterfaceApi{

ListqueryCats(Stringquery);

Uristore(Catcat);

}

看起来很简单吧! 现在开始编写我们的业务逻辑。

Java

public class CatsHelper {

Api api;

public Uri saveTheCutestCat(String query){

List cats = api.queryCats(query);

Cat cutest = findCutest(cats);

Uri savedUri = api.store(cutest);

return savedUri;

}

private Cat findCutest(List cats) {

return Collections.max(cats);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

publicclassCatsHelper{

Apiapi;

publicUrisaveTheCutestCat(Stringquery){

Listcats=api.queryCats(query);

Catcutest=findCutest(cats);

UrisavedUri=api.store(cutest);

returnsavedUri;

}

privateCatfindCutest(Listcats){

returnCollections.max(cats);

}

}

(@ο@) 哇~,这也太简单太清晰了吧!来看看上面的代码是多么的酷。主要的函数 saveTheCutestCat  只包含了 3个函数调用。使用参数来调用这些函数,并接收返回的参数。 并且等待每个函数执行并返回结果。

如此简单、如此有效。下面来看看这种简单函数的其他优点。

组合(Composition)

可以看到我们的 saveTheCutestCat 由其他三个函数调用所组成的。我们通过函数来把一个大功能分割为每个容易理解的小功能。通过函数调用来组合使用这些小功能。使用和理解起来都相当简单。

异常传递

另外一个使用函数的好处就是方便处理异常。每个函数都可以通过抛出异常来结束运行。该异常可以在抛出异常的函数里面处理,也可以在调用该函数的外面处理,所以我们无需每次都处理每个异常,我们可以在一个地方处理所有可能抛出的异常。

Java

try{

List cats = api.queryCats(query);

Cat cutest = findCutest(cats);

Uri savedUri = api.store(cutest);

return savedUri;

} catch (Exception e) {

e.printStackTrace()

return someDefaultValue;

}

1

2

3

4

5

6

7

8

9

try{

Listcats=api.queryCats(query);

Catcutest=findCutest(cats);

UrisavedUri=api.store(cutest);

returnsavedUri;

}catch(Exceptione){

e.printStackTrace()

returnsomeDefaultValue;

}

这样,我们就可以处理这三个函数中所抛出的任何异常了。如果没有 try catch 语句,我们也可以把异常继续传递下去。

向异步进军

但是,现实世界中我们往往没法等待。有些时候你没法只使用阻塞调用。在 Android 中你需要处理各种异步操作。

就拿 Android 的 OnClickListener 接口来说吧, 如果你需要处理一个 View 的点击事件,你必须提供一个 该 Listener 的实现来处理用户的点击事件。下面来看看如何处理异步调用。

异步网络调用

假设我们的 cats-sdk.jar 使用了异步调用的 API 来访问网络资源,例如使用 Ion来异步访问网络。

这样我们的新 API 接口就变为这样了:

Java

public interface Api {

interface CatsQueryCallback {

void onCatListReceived(List cats);

void onError(Exception e);

}

void queryCats(String query, CatsQueryCallback catsQueryCallback);

Uri store(Cat cat);

}

1

2

3

4

5

6

7

8

9

10

11

publicinterfaceApi{

interfaceCatsQueryCallback{

voidonCatListReceived(Listcats);

voidonError(Exceptione);

}

voidqueryCats(Stringquery,CatsQueryCallbackcatsQueryCallback);

Uristore(Catcat);

}

这样我们查询猫的操作就变为异步的了, 通过 CatsQueryCallback  回调接口来结束查询的数据和处理异常情况。

我们的业务逻辑也需要跟着改变一下:

Java

public class CatsHelper {

public interface CutestCatCallback {

void onCutestCatSaved(Uri uri);

void onQueryFailed(Exception e);

}

Api api;

public void saveTheCutestCat(String query, CutestCatCallback cutestCatCallback){

api.queryCats(query, new Api.CatsQueryCallback() {

@Override

public void onCatListReceived(List cats) {

Cat cutest = findCutest(cats);

Uri savedUri = api.store(cutest);

cutestCatCallback.onCutestCatSaved(savedUri);

}

@Override

public void onError(Exception e) {

cutestCatCallback.onQueryFailed(e);

}

});

}

private Cat findCutest(List cats) {

return Collections.max(cats);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

publicclassCatsHelper{

publicinterfaceCutestCatCallback{

voidonCutestCatSaved(Uriuri);

voidonQueryFailed(Exceptione);

}

Apiapi;

publicvoidsaveTheCutestCat(Stringquery,CutestCatCallbackcutestCatCallback){

api.queryCats(query,newApi.CatsQueryCallback(){

@Override

publicvoidonCatListReceived(Listcats){

Catcutest=findCutest(cats);

UrisavedUri=api.store(cutest);

cutestCatCallback.onCutestCatSaved(savedUri);

}

@Override

publicvoidonError(Exceptione){

cutestCatCallback.onQueryFailed(e);

}

});

}

privateCatfindCutest(Listcats){

returnCollections.max(cats);

}

}

这样我们就没法使用阻塞式函数调用了, 我们无法继续使用阻塞调用来使用这些 API 了(当然了,万事无绝对,如果你使用 synchronized, CountdownLatch 等方式来阻塞线程,你还是可以继续使用,本文我们需要处理异步方式来理解这些概念。) 所以,我们没法让 saveTheCutestCat 函数返回一个值了, 我们需要一个回调接口来异步的处理结果。

这里我们再进一步,使用两个异步操作来实现我们的功能, 例如 我们还使用异步 IO 来写文件。

Java

public interface Api {

interface CatsQueryCallback {

void onCatListReceived(List cats);

void onQueryFailed(Exception e);

}

interface StoreCallback{

void onCatStored(Uri uri);

void onStoreFailed(Exception e);

}

void queryCats(String query, CatsQueryCallback catsQueryCallback);

void store(Cat cat, StoreCallback storeCallback);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

publicinterfaceApi{

interfaceCatsQueryCallback{

voidonCatListReceived(Listcats);

voidonQueryFailed(Exceptione);

}

interfaceStoreCallback{

voidonCatStored(Uriuri);

voidonStoreFailed(Exceptione);

}

voidqueryCats(Stringquery,CatsQueryCallbackcatsQueryCallback);

voidstore(Catcat,StoreCallbackstoreCallback);

}

业务逻辑变为:

Java

public class CatsHelper {

public interface CutestCatCallback {

void onCutestCatSaved(Uri uri);

void onError(Exception e);

}

Api api;

public void saveTheCutestCat(String query, CutestCatCallback cutestCatCallback){

api.queryCats(query, new Api.CatsQueryCallback() {

@Override

public void onCatListReceived(List cats) {

Cat cutest = findCutest(cats);

api.store(cutest, new Api.StoreCallback() {

@Override

public void onCatStored(Uri uri) {

cutestCatCallback.onCutestCatSaved(uri);

}

@Override

public void onStoreFailed(Exception e) {

cutestCatCallback.onError(e);

}

});

}

@Override

public void onQueryFailed(Exception e) {

cutestCatCallback.onError(e);

}

});

}

private Cat findCutest(List cats) {

return Collections.max(cats);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

publicclassCatsHelper{

publicinterfaceCutestCatCallback{

voidonCutestCatSaved(Uriuri);

voidonError(Exceptione);

}

Apiapi;

publicvoidsaveTheCutestCat(Stringquery,CutestCatCallbackcutestCatCallback){

api.queryCats(query,newApi.CatsQueryCallback(){

@Override

publicvoidonCatListReceived(Listcats){

Catcutest=findCutest(cats);

api.store(cutest,newApi.StoreCallback(){

@Override

publicvoidonCatStored(Uriuri){

cutestCatCallback.onCutestCatSaved(uri);

}

@Override

publicvoidonStoreFailed(Exceptione){

cutestCatCallback.onError(e);

}

});

}

@Override

publicvoidonQueryFailed(Exceptione){

cutestCatCallback.onError(e);

}

});

}

privateCatfindCutest(Listcats){

returnCollections.max(cats);

}

}

现在再来看看我们的业务逻辑代码,是不是和之前的阻塞式调用那么简单、那么清晰? 当然不一样了,上面的异步操作代码看起来太恐怖了! 这里有太多的干扰代码了,太多的匿名类了,但是不可否认,他们的业务逻辑其实是一样的。查询猫的列表数据、找出最可爱的并保持其图片。

组合功能也不见了! 现在你没法像阻塞操作一样来组合调用每个功能了。异步操作中,每次你都必须通过回调接口来手工的处理结果。

那么关于异常传递和处理呢? 没了!异步代码中的异常不会自动传递了,我们需要手工的重新传递出去。(onStoreFailed 和 onQueryFailed 就是干这事用的)

上面的代码非常难懂也更难发现潜在的 BUG。

然后呢?我们如何处理这种情况呢?我们是不是就被困在这种无法组合的回调接口困局中呢? 下次我们来看看如何优化该问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值