本系列文章:
- 拆轮子系列--RxJava前奏篇
- 拆轮子系列--RxJava理解(一)--Map解析
- 拆轮子系列--RxJava理解(二)--subscribeOn
- 拆轮子系列--RxJava理解(三)--observeOn
本篇文章主要介绍为什么要使用RxJava,属于RxJava理解的前奏篇。本文大纲如下:
-
- RxJava的常规写法
-
- 一个具体的例子---从普通写法逐渐演变成RxJava写法
-
- 总结
1. RxJava 的常规写法
有人说RxJava非常好用,那么,它究竟好用在哪里?今天来具体分析下。首先,先来阐述RxJava到底是什么,RxJava官方的解释是:“a library for composing asynchronous and event-based programs using observable sequences for the Java VM”,其核心就是“asynchronous”这个词,直白的说,RxJava就是一个实现异步操作的库。那为什么大家会觉得RxJava好用,而不是使用AsyncTask/Handler...?这里可以归结一个词,简洁。举个例子,我们要从网络上获取图片然后显示。利用AsyncTask的做法是这样的:
public class ImageTask extends AsyncTask {
@Override
protected Bitmap doInBackground(String... params) {
String imageUrl = params[0];
try {
URL url = new URL(imageUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream is = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
if (bitmap != null) {
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if(bitmap!=null){
showBitMap();
}
}
}
如果将这个需求用RxJava实现会是怎么样?我们先实现看看:
Observable.just(imageUrl)
.map(new Func1() {
@Override
public Bitmap call(String url) {
return getBitmapFromUrl(url);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1() {
@Override
public void call(Bitmap bitmap) {
showBitMap();
}
});
可能有的朋友要说话了没看出什么区别啊,好用个毛线啊
。其实,我们观察下就能发现,RxJava的这个实现,是一条链式调用,在逻辑上没有任何的嵌套,简单明了。更进一步说,当我们需求变得复杂时,比如在大量的图片资源中选择一张,亦或者是选择前几张图片的时候,你还能在你那片代码中能迅速理清逻辑,并快速调整?RxJava在处理复杂逻辑时,一条链式调用,虽然很长,但胜在逻辑清晰。
2. 一个具体的例子---从普通写法逐渐演变成RxJava写法
接下来,以一个例子具体阐述下RxJava到底逻辑清晰在哪里。假设有一个需求:谁是最可爱的人
(SB需求,哈哈哈)。该需求大体就是网络请求查询一组图片,每张图片有一个可爱系数(一个整型值),而我们的任务,就是下载一组可爱人的照片集合,然后选择最可爱的那个。
好了,需求弄明白了接下来就进行实现吧,先定义一个简单的数据结构:
public class CutestPeople implements Comparable {
private Bitmap image;
private int cuteness;
@Override
public int compareTo(CutestPeople cutestPeople) {
return Integer.compare(cuteness, cutestPeople.cuteness);
}
}
然后,提供两个接口,查询与保存:
public interface QueryApi {
/**
* 查询可爱的人
*/
List queryCuestPeople(String query);
/**
* 获取需要保存的Uri
*/
Uri store(CutestPeople people);
}
好了,大体结构基本完成,接下来定义一个帮助类,该类就是调用前面定义的方法获取结果:
public class DataHelper {
private QueryApi mApi;
public Uri saveTheCutestPeople(String query) {
List cutestPeoples = mApi.queryCuestPeople(query);
CutestPeople cutestPeople = findCutestPeople(cutestPeoples);
Uri savedUrl = mApi.store(cutestPeople);
return savedUrl;
}
/**
* 获取最可爱的人
*/
public CutestPeople findCutestPeople(List people) {
return Collections.max(people);
}
}
上面似乎完成了?不对,还有一个问题,加上异常处理机制:
try {
List cutestPeoples = mApi.queryCuestPeople(query);
CutestPeople cutestPeople = findCutestPeople(cutestPeoples);
Uri savedUrl = mApi.store(cutestPeople);
return savedUrl;
} catch (Exception e) {
e.printStackTrace();
return error;
}
到这里,需求算是大体完成了,程序可以跑起来了。但是,有没有发现,以上的代码还有很大的优化空间,比如,我们在接口里面定义异步回调机制,这样程序运行的结果或者异常都可以从回调中拿到:
public interface QueryApi {
interface CuestPeopleQueryCallback {
void onCuestPeopleReceived(List people);
void onQueryError(Exception e);
}
interface StoreCallback {
void onCuestPeopleStore(Uri uri);
void onStoreError(Exception e);
}
/**
* 获取可爱人儿集合
*
*/
List queryCutestPeople(String query, CutestPeopleQueryCallback callback);
/**
* 保存最可爱的人到本地
*
*/
Uri store(CutestPeople people, StoreCallback callback);
}
既然接口发生了改变,那么相应的DataHelper类的逻辑也要发生改变,继续修改:
public class DataHelper {
private QueryApi mApi;
public void saveTheCuestPeople(String query, final CutestPeopleCallback cutestCallback) {
mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
@Override
public void onCutestPeopleReceived(List people) {
CutestPeople cutestPeople = findCutestPeople(people);
mApi.store(cutestPeople, new QueryApi.StoreCallback() {
@Override
public void onCutestPeopleStore(Uri uri) {
cutestPeopleCallback.onCutestPeopleSaved(uri);
}
@Override
public void onStoreError(Exception e) {
cutestPeopleCallback.onError(e);
}
});
}
@Override
public void onQueryError(Exception e) {
cutestPeopleCallback.onError(e);
}
});
}
/**
* 获取最可爱的人
*/
public CutestPeople findCutestPeople(List people) {
return Collections.max(people);
}
/**
* 最可爱的人保存结果回调
*/
public interface CutestPeopleCallback {
void onCutestPeopleSaved(Uri uri);
void onError(Exception e);
}
}
经过上面的修改,代码看起来是不是好了很多。可是,有没有发现接口调用的太多了,而且在每一个关键点都需要手动的插入相应的接口回调,而且,错误传递机制也木有。这样子还不行,需要继续优化。目前的情况看,我们QuaryApi
中的接口是这个样子的:
void onCutestPeopleReceived(List people);
void onCutestPeopleStore(Uri uri);
...
void onQueryError(Exception e);
void onStoreError(Exception e);
这个时候已经定义的接口方法是不能改变了,但是,我们可以在不改变方法的前提下对接口进行包装:
public interface Callback {
void onGetResult(T result);
void onError(Exception e);
}
继续搞事情,将之前定义的QueryApi进行包装下:
public class ApiWarpper {
private QueryApi mApi;
public void queryQuestPeople(String query, final MyCallback> myCallback) {
mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
@Override
public void onCutestPeopleReceived(List people) {
myCallback.onGetResult(people);
}
@Override
public void onQueryError(Exception e) {
myCallback.onError(e);
}
});
}
public void storeUri(CutestPeople people, final MyCallback myCallback) {
mApi.store(people, new QueryApi.StoreCallback() {
@Override
public void onCutestPeopleStore(Uri uri) {
myCallback.onGetResult(uri);
}
@Override
public void onStoreError(Exception e) {
myCallback.onError(e);
}
});
}
}
在对QueryApi
进行包装之后,我们再来修改下DataHelper
中的逻辑,调整如下:
public class DataHelper {
ApiWrapper mApiWrapper;
public void saveTheCutestPeople(String query, final MyCallback myCallBack) {
mApiWrapper.queryQuestPeople(query, new MyCallback>() {
@Override
public void onGetResult(List result) {
CutestPeople cutestPeople = findCutestPeople(result);
mApiWrapper.storeUri(cutestPeople, myCallBack);
}
@Override
public void onError(Exception e) {
myCallBack.onError(e);
}
});
}
/**
* 获取最可爱的人
*/
public CutestPeople findCutestPeople(List people) {
return Collections.max(people);
}
}
好了,到了这一步基本上没什么问题,需求已经完成。但是,没错还有但是,我们可以想想,能不能将每个异步操作分解成更小的粒子,也就是说,每个异步操作只携带一个参数对象,然后返回携带者回调信息的临时变量。
接下来定义一个通用的临时变量,该对象只是携带一个参数:
public abstract class MyAsyncTask {
public abstract void start(MyCallback callback);
}
修改ApiWrapper
中的方法,将异步请求分解成更小的粒子:
public class ApiWrapper {
private QueryApi mApi;
public MyAsyncTask> queryQuestPeople(final String query) {
//这里做了修改,传入一个参数,返回一个临时变量
return new MyAsyncTask>() {
@Override
public void start(final MyCallback> callback) {
mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
@Override
public void onCutestPeopleReceived(List people) {
callback.onGetResult(people);
}
@Override
public void onQueryError(Exception e) {
callback.onError(e);
}
});
}
};
}
public MyAsyncTask storeUri(final CutestPeople people){
//这里做了修改,传入一个参数,返回一个临时变量
return new MyAsyncTask() {
@Override
public void start(final MyCallback callback) {
mApi.store(people, new QueryApi.StoreCallback() {
@Override
public void onCutestPeopleStore(Uri uri) {
callback.onGetResult(uri);
}
@Override
public void onStoreError(Exception e) {
callback.onError(e);
}
});
}
};
}
}
改了ApiWrapper
当然同步的需要修改DataHelper
这个类:
public class DataHelper {
ApiWrapper mApiWrapper;
public MyAsyncTask saveTheCuestPeople(final String query) {
final MyAsyncTask> listMyAsyncTask = mApiWrapper.queryQuestPeople(query);
final MyAsyncTask myCutestAsyncTask = new MyAsyncTask() {
@Override
public void start(final MyCallback callback) {
listMyAsyncTask.start(new MyCallback>){
@Override
public void onGetResult(List result) {
callback.onGetResult(findCutestPeople(result));
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
MyAsyncTask uriMyAsyncTask = new MyAsyncTask() {
@Override
public void start(final MyCallback callback) {
myCutestAsyncTask.start(new MyCallback() {
@Override
public void onGetResult(CutestPeople result) {
mApiWrapper.storeUri(result)
.start(new MyCallback() {
@Override
public void onGetResult(Uri result) {
callback.onGetResult(result);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
return uriMyAsyncTask;
}
/**
* 获取可爱的人
*/
public CutestPeople findCutestPeople(List people) {
return Collections.max(people);
}
}
修改之后似乎变得比之前要复杂,我们回顾最初我们写的代码:
public class DataHelper {
private QueryApi mApi;
public Uri saveTheCutestPeople(String query) {
List cutestPeoples = mApi.queryCuestPeople(query);
CutestPeople cutestPeople = findCutestPeople(cutestPeoples);
Uri savedUrl = mApi.store(cutestPeople);
return savedUrl;
}
/**
* 获取最可爱的人
*/
public CutestPeople findCutestPeople(List people) {
return Collections.max(people);
}
}
将我们最后修改的代码简化下:
public class DataHelper {
ApiWrapper mApiWrapper;
public MyAsyncTask saveTheCuestPeople(final String query) {
final MyAsyncTask> listMyAsyncTask = mApiWrapper.queryQuestPeople(query);
final MyAsyncTask myCutestAsyncTask = new MyAsyncTask() { ...};
MyAsyncTask uriMyAsyncTask = new MyAsyncTask() {...};
return uriMyAsyncTask;
}
/**
* 获取最可爱的人
*/
public CutestPeople findCutestPeople(List people) {
return Collections.max(people);
}
}
对比上面两份代码我们发现,其实大体的逻辑是保持一致的,区别就是我们将异步操作细分成了更小的模块,然后组合在一起,最后返回一个组合后的结果对象而已。
写了这么多,好像跟RxJava没有什么关系啊,别急,下面我们用RxJava来实现这个需求:
public class ApiWrapper {
private QueryApi mApi;
public Observable> queryQuestPeople(final String query) {
return Observable.create(new Observable.OnSubscribe>() {
@Override
public void call(final Subscriber super List> subscriber) {
mApi.queryCutestPeople(query, new QueryApi.CutestPeopleQueryCallback() {
@Override
public void onCutestPeopleReceived(List people) {
subscriber.onNext(people);
}
@Override
public void onQueryError(Exception e) {
subscriber.onError(e);
}
});
}
});
}
public Observable storeUri(final CutestPeople people) {
return Observable.create(new Observable.OnSubscribe() {
@Override
public void call(final Subscriber super Uri> subscriber) {
mApi.store(people, new QueryApi.StoreCallback() {
@Override
public void onCutestPeopleStore(Uri uri) {
subscriber.onNext(uri);
}
@Override
public void onStoreError(Exception e) {
subscriber.onError(e);
}
});
}
});
}
}
DataHelper类:
public class DataHelper {
ApiWrapper mApiWrapper;
public Observable saveTheCuestPeople(String query) {
Observable> listObservable = mApiWrapper.queryQuestPeople(query);
Observable cutestPeople = listObservable.map(new Func1, CutestPeople>() {
@Override
public CutestPeople call(List cutestPeoples) {
return findCutestPeople(cutestPeoples);
}
});
Observable storeObservable = cutestPeople.flatMap(new Func1>() {
@Override
public Observable call(CutestPeople people) {
return mApiWrapper.storeUri(people);
}
});
return storeObservable;
}
/**
* 获取最可爱的人
*/
public CutestPeople findCutestPeople(List people) {
return Collections.max(people);
}
}
看到上面的逻辑,是否发现跟我们最后写的逻辑基本一致?而区别就是利用RxJava将一个个的异步操作单独的抽象出来,这样我们就能避免各种嵌套的回调,然后将这些抽象出来的异步操作进行组合作为一个结果返回即可。
3. 总结
RxJava的核心思想就是处理异步操作,将异步操作独立的抽象出来,在异步条件非常复杂的情况下,RxJave以一条链式调用将所有复杂的异步操作串成一条线,从而实现代码的易读性与简洁性。