概述
Rxjava和RxAndroid在安卓开发中越来越常见了,函数式编程的思想和编码方式写起代码来还是非常爽的,今天这篇文章,不会去介绍RxJava的使用,而是去介绍RxJava的思想是怎么从我们原始的编码思想中演变出来的。
引文
首先引入一篇很优秀的帖子http://www.devtf.cn/?p=323,楼主的这篇帖子算是用自己的思维把原文给翻译了一遍。
正文
上代码:
/**
* 学生
*/
public class Student {
String name;// 名字
int age;// 年龄
}
/**
* Api调用
*/
public interface Api {
/**
* 通过一个query条件查找出多个学生
*/
List<Student> queryStudents(String query);
/**
* 保存一个学生的信息,会返回一个Uri值
*/
Uri save(Student student);
}
/**
* 学生的管理类
*/
public class StudentHelper {
Api api;
/**
* 保存最棒的学生
*/
public Uri saveTheBestStudent(String query) {
// 加一个异常处理
try {
List<Student> students = api.queryStudents(query);
Student bestStudent = findBestStudent(students);
return api.save(bestStudent);
} catch (Exception e) {
e.printStackTrace();
return null;// 保存出错时返回一个默认的值
}
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
很正常的代码,现在加需求,我要在查询学生和保存学生的时候加回调操作,需要修改Api
/**
* Api调用
*/
public interface Api {
/**
* 查询学生回调
*/
interface QueryStudentCallBack {
void onStudentsReceived(List<Student> students);// 查询成功并返回结果
void onQueryError(Exception e);// 查询出错
}
/**
* 保存学生回调
*/
interface SaveCallBack {
void onStudentSaved(Uri uri);// 保存成功并返回结果
void onSaveError(Exception e);// 保存出错
}
/**
* 通过一个query条件查找出多个学生
*/
List<Student> queryStudents(String query, QueryStudentCallBack queryStudentCallBack);
/**
* 保存一个学生的信息,会返回一个Uri值
*/
Uri save(Student student, SaveCallBack saveCallBack);
}
StudentHelper中的saveTheBestStudent()方法包含了查询学生列表、查询出最棒的学生、保存最棒的学生这三件事情,我们来给它加上一个保存最棒学生的回调,修改后的StudentHelper类
/**
* 学生的管理类
*/
public class StudentHelper {
public interface SaveTheBestStudentCallBack {
void onBestStudentSaved(Uri uri);// 保存最棒的学生成功并返回Uri
void onBestStudentSavedError(Exception e);// 保存最棒的学生时出错了
}
Api api;
/**
* 保存最棒的学生
*/
public void saveTheBestStudent(String query, SaveTheBestStudentCallBack saveTheBestStudentCallBack) {
api.queryStudents(query, new Api.QueryStudentCallBack() {
@Override
public void onStudentsReceived(List<Student> students) {
Student bestStudent = findBestStudent(students);
api.save(bestStudent, new Api.SaveCallBack() {
@Override
public void onStudentSaved(Uri uri) {
saveTheBestStudentCallBack.onBestStudentSaved(uri);
}
@Override
public void onSaveError(Exception e) {
saveTheBestStudentCallBack.onBestStudentSavedError(e);
}
});
}
@Override
public void onQueryError(Exception e) {
saveTheBestStudentCallBack.onBestStudentSavedError(e);
}
});
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
由于我们在回调中就可以把结果给返回出去了,所以我们把相关的方法的返回类型改成void:
1. StudentHelper中的public void saveTheBestStudent(…)
2. Api中的两个方法,void queryStudents(…),void save(…)
到目前为止,由于这段代码是我们一个一个敲出来的,所以我们对它的逻辑还是比较清楚的,但是乍一看上去代码是比较混乱的,各种未知的大小括号包着,各种蜜汁缩进,我都不确定过几天再来看这段代码的时候还能不能一下子看出逻辑来,要是换做我们实际项目中开发如果逻辑更多的话,第一想法肯定是:这他么写的什么玩意儿??如果还要更改逻辑的话简直是噩梦,且很容易出BUG。所以,让我们来改进吧!
改进之路
上面的代码中有3个回调,其实他们都做了2个类似的事情:
1. 做某件事情然后返回结果(onBestStudentSaved,onStudentsReceived,onStudentSaved)
2. 出错时的回调(onBestStudentSavedError,onQueryError,onSaveError)
当出现这种类似或者重复的操作的时候就是我们该重构的时候了。
我们可以用一个泛型接口来封装一下:
/**
* 泛型回调接口
*/
public interface CallBack<T> {
void onResult(T result);
void onError(Exception e);
}
回调接口修改为通用的之后,相应的,来修改一下StudentHelper,我们先前自定义的SaveTheBestStudentCallBack接口就可以去掉了,修改后为:
/**
* 学生的管理类
*/
public class StudentHelper {
Api api;
/**
* 保存最棒的学生
*/
public void saveTheBestStudent(String query, CallBack<Uri> saveTheBestStudentCallBack) {
api.queryStudents(query, new Api.QueryStudentCallBack() {
@Override
public void onStudentsReceived(List<Student> students) {
Student bestStudent = findBestStudent(students);
api.save(bestStudent, new Api.SaveCallBack() {
@Override
public void onStudentSaved(Uri uri) {
saveTheBestStudentCallBack.onResult(uri);
}
@Override
public void onSaveError(Exception e) {
saveTheBestStudentCallBack.onError(e);
}
});
}
@Override
public void onQueryError(Exception e) {
saveTheBestStudentCallBack.onError(e);
}
});
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
先前我们只有Api和StudentHelper这2个调用类,现在我们新增一个ApiWrapper类来做Api和Student的中间类来简化代码,把Api的相关调用丢到ApiWrapper中,然后把queryStudents和save分开,制作为提供调用,实际调用由StudentHelper去调
/**
* Api包装类,Api和StudentHelper的中间类
*/
public class ApiWrapper {
Api api;
public void queryStudents(String query, CallBack<List<Student>> queryStudentCallBack) {
api.queryStudents(query, new Api.QueryStudentCallBack() {
@Override
public void onStudentsReceived(List<Student> students) {
queryStudentCallBack.onResult(students);
}
@Override
public void onQueryError(Exception e) {
queryStudentCallBack.onError(e);
}
});
}
public void save(Student student, CallBack<Uri> saveCallBack) {
api.save(student, new Api.SaveCallBack() {
@Override
public void onStudentSaved(Uri uri) {
saveCallBack.onResult(uri);
}
@Override
public void onSaveError(Exception e) {
saveCallBack.onError(e);
}
});
}
}
那么在StudentHelper类中就可以把原来的Api换成ApiWrapper了:
/**
* 学生的管理类
*/
public class StudentHelper {
ApiWrapper apiWrapper;
/**
* 保存最棒的学生
*/
public void saveTheBestStudent(String query, CallBack<Uri> saveTheBestStudentCallBack) {
apiWrapper.queryStudents(query, new CallBack<List<Student>>() {
@Override
public void onResult(List<Student> result) {
apiWrapper.save(findBestStudent(result), saveTheBestStudentCallBack);
}
@Override
public void onError(Exception e) {
saveTheBestStudentCallBack.onError(e);
}
});
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
加了ApiWrapper之后,StudentHelper的代码就简化了很多,看起来也舒服很多了,逻辑上也变得清晰了,到现在为止这样的写法已经很适合我们的需求了,但是,你没有感觉还差点什么吗?既然都做到这样的地步了,加入我们下次还遇到类似的需求,它的方法中要传入的参数不是String类型的query,而是int类型的query或者其他的呢。我们是否可以把这种模式的通用性做的更强?
上面我们把回调通过泛型做成了通用的模式,那现在这里,我们Api类的queryStudents方法、save方法还有StudentHelper类中的saveTheBestStudent方法他们是不是都是同一种模式呢?都是一个普通的参数加上一个回调参数,现在回调参数我们写好了,那么来把普通的参数也来改变一下吧。
原文中有这样一段话:任何异步操作需要携带所需的常规参数和一个回调实例对象。如果我们试图去分开这几个阶段,每个异步操作仅仅将会携带一个参数对象,然后返回一些携带着回调(信息)的临时对象。
简单来说是是这样的:把请求参数变为一个,把回调信息的对象作为方法的返回值传出去。
这里我们又新增一个抽象类AsyncJob来作为这个回调信息的对象,然后把原来方法中的CallBack回调放到这个抽象类的start方法中,由于start方法是抽象的,所以实例化AsyncJob的时候会被强制要求实现start方法来尝试修改一下:
public abstract class AsyncJob<T> {
public abstract void start(CallBack<T> callback);
}
这里为什么用抽象类呢?其实这个地方用接口也是可以的:
public interface AsyncJob<T> {
void start(CallBack<T> callback);
}
原因是因为。。。。等下会有非抽象方法加入进来。。。
好的,接下来我们把saveTheBestStudent、ApiWrapper的queryStudents和save修改一下,就像我们先前说的,这几个方法其实是同一种模式的,然后把方法的参数变为一个,把AsyncJob作为临时返回值
/**
* Api包装类,Api和StudentHelper的中间类
*/
public class ApiWrapper {
Api api;
public AsyncJob<List<Student>> queryStudents(String query) {
return new AsyncJob<List<Student>>() {
@Override
public void start(CallBack<List<Student>> callback) {
api.queryStudents(query, new Api.QueryStudentCallBack() {
@Override
public void onStudentsReceived(List<Student> students) {
callback.onResult(students);
}
@Override
public void onQueryError(Exception e) {
callback.onError(e);
}
});
}
};
}
public AsyncJob<Uri> save(Student student) {
return new AsyncJob<Uri>() {
@Override
public void start(CallBack<Uri> callback) {
api.save(student, new Api.SaveCallBack() {
@Override
public void onStudentSaved(Uri uri) {
callback.onResult(uri);
}
@Override
public void onSaveError(Exception e) {
callback.onError(e);
}
});
}
};
}
}
然后StudnetWrapper:
/**
* 学生的管理类
*/
public class StudentHelper {
ApiWrapper apiWrapper;
/**
* 保存最棒的学生
*/
public AsyncJob<Uri> saveTheBestStudent(String query) {
return new AsyncJob<Uri>() {
@Override
public void start(CallBack<Uri> callback) {
apiWrapper.queryStudents(query).start(new CallBack<List<Student>>() {
@Override
public void onResult(List<Student> result) {
apiWrapper.save(findBestStudent(result)).start(new CallBack<Uri>() {
@Override
public void onResult(Uri result) {
callback.onResult(result);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
这一步,代码形式的转变还是很明显的,首先方法的参数又原来的两个变成了一个,然后原来方法参数中的回调方法放到了AsyncJob的start方法中调用,最后方法的返回值由原来的void变成了现在的AsyncJob
把StudentHelper再转换一下:
/**
* 学生的管理类
*/
public class StudentHelper {
ApiWrapper apiWrapper;
/**
* 保存最棒的学生
*/
public AsyncJob<Uri> saveTheBestStudent(String query) {
AsyncJob<List<Student>> studentsAsync = apiWrapper.queryStudents(query);
AsyncJob<Student> studentAsync = new AsyncJob<Student>() {
@Override
public void start(CallBack<Student> callback) {
studentsAsync.start(new CallBack<List<Student>>() {
@Override
public void onResult(List<Student> result) {
callback.onResult(findBestStudent(result));
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
AsyncJob<Uri> uriAsync = new AsyncJob<Uri>() {
@Override
public void start(CallBack<Uri> callback) {
studentAsync.start(new CallBack<Student>() {
@Override
public void onResult(Student result) {
apiWrapper.save(result).start(new CallBack<Uri>() {
@Override
public void onResult(Uri result) {
callback.onResult(result);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
return uriAsync;
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
然后我们再来看一下saveTheBestStudent方法中的这段代码:
AsyncJob<List<Student>> studentsAsync = apiWrapper.queryStudents(query);
AsyncJob<Student> studentAsync = new AsyncJob<Student>() {
@Override
public void start(CallBack<Student> callback) {
studentsAsync.start(new CallBack<List<Student>>() {
@Override
public void onResult(List<Student> result) {
callback.onResult(findBestStudent(result));
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
有没有感觉其实就是AsyncJob
public interface Func<T, R> {
R call(T t);
}
相当简单,Func接口有两个类型成员,T对应于参数类型而R对应于返回类型。
先前说到前面那段代码的作用就是两个AsynJob对象的转换,我们大概可以这样想:AsynJobB = AsynJobA.map()这样的转换公式,所以要把公共的代码提取到AsynJob中:
public <R>AsyncJob<R> map(Func<T,R> func){
final AsyncJob<T> source = this;
return new AsyncJob<R>() {
@Override
public void start(CallBack<R> callback) {
source.start(new CallBack<T>() {
@Override
public void onResult(T result) {
R map = func.call(result);
callback.onResult(map);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
}
修改一下StudentHelper
/**
* 学生的管理类
*/
public class StudentHelper {
ApiWrapper apiWrapper;
/**
* 保存最棒的学生
*/
public AsyncJob<Uri> saveTheBestStudent(String query) {
AsyncJob<List<Student>> studentsAsync = apiWrapper.queryStudents(query);
AsyncJob<Student> studentAsync = studentsAsync.map(new Func<List<Student>, Student>() {
@Override
public Student call(List<Student> students) {
return findBestStudent(students);
}
}) ;
AsyncJob<Uri> uriAsync = new AsyncJob<Uri>() {
@Override
public void start(CallBack<Uri> callback) {
studentAsync.start(new CallBack<Student>() {
@Override
public void onResult(Student result) {
apiWrapper.save(result).start(new CallBack<Uri>() {
@Override
public void onResult(Uri result) {
callback.onResult(result);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
return uriAsync;
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
这样改了之后是不是看着非常的爽,转换的过程全部在内部,你只需要提供转换的值就行了,让我们用Lambda表达式看一下
AsyncJob<List<Student>> studentsAsync = apiWrapper.queryStudents(query);
AsyncJob<Student> studentAsync = studentsAsync.map(students -> findBestStudent(students));
天哪,这是有多简洁!
接下来我们尝试对这段代码进行修改
AsyncJob<Uri> uriAsync = new AsyncJob<Uri>() {
@Override
public void start(CallBack<Uri> callback) {
studentAsync.start(new CallBack<Student>() {
@Override
public void onResult(Student result) {
apiWrapper.save(result).start(new CallBack<Uri>() {
@Override
public void onResult(Uri result) {
callback.onResult(result);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
可以改成这样
AsyncJob<Uri> uriAsync = studentAsync.map(
new Func<Student, Uri>() {
@Override
public Uri call(Student student) {
return apiWrapper.save(student);
}
}
) ;
但是会报错,因为我们希望的是返回AsyncJob类型,但是实际上call方法返回的是Uri类型,这就尴尬了。没办法了,要在AsyncJob中增加另外一个方法来完成这种转换了
public abstract class AsyncJob<T> {
public abstract void start(CallBack<T> callback);
public <R>AsyncJob<R> map(Func<T,R> func){
final AsyncJob<T> source = this;
return new AsyncJob<R>() {
@Override
public void start(CallBack<R> callback) {
source.start(new CallBack<T>() {
@Override
public void onResult(T result) {
R map = func.call(result);
callback.onResult(map);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
}
public <R>AsyncJob<R> flatMap(Func<T,AsyncJob<R>> func){
final AsyncJob<T> source = this;
return new AsyncJob<R>() {
@Override
public void start(CallBack<R> callback) {
source.start(new CallBack<T>() {
@Override
public void onResult(T result) {
AsyncJob<R> mapped = func.call(result);
mapped.start(new CallBack<R>() {
@Override
public void onResult(R result) {
callback.onResult(result);
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
@Override
public void onError(Exception e) {
callback.onError(e);
}
});
}
};
}
}
首先方法的参数Func的类型由Func
/**
* 学生的管理类
*/
public class StudentHelper {
ApiWrapper apiWrapper;
/**
* 保存最棒的学生
*/
public AsyncJob<Uri> saveTheBestStudent(String query) {
AsyncJob<List<Student>> studentsAsync = apiWrapper.queryStudents(query);
AsyncJob<Student> studentAsync = studentsAsync.map(new Func<List<Student>, Student>() {
@Override
public Student call(List<Student> students) {
return findBestStudent(students);
}
});
AsyncJob<Uri> uriAsync = studentAsync.flatMap(new Func<Student, AsyncJob<Uri>>() {
@Override
public AsyncJob<Uri> call(Student student) {
return apiWrapper.save(student);
}
});
return uriAsync;
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
Lambda表达式终极简化版本:
/**
* 学生的管理类
*/
public class StudentHelper {
ApiWrapper apiWrapper;
/**
* 保存最棒的学生
*/
public AsyncJob<Uri> saveTheBestStudent(String query) {
AsyncJob<List<Student>> studentsAsync = apiWrapper.queryStudents(query);
AsyncJob<Student> studentAsync = studentsAsync.map(this::findBestStudent);
AsyncJob<Uri> uriAsync = studentAsync.flatMap(student -> apiWrapper.save(student));
return uriAsync;
}
/**
* 查找最棒的学生
*/
public Student findBestStudent(List<Student> students) {
return students.get(0);// 此处逻辑可随意些,这里我随便写了一种
}
}
到这里,基本的原理我们就理完了,我建议大家跟着这个逻辑自己动手敲一遍,去理解大神是怎样的思考方式得到这样的结果的。接下来我们结合RxJava看一下,这里我就引用原文的内容了
- AsyncJob 就是实际上的 Observable,它不仅可以只分发一个单一的结果也可以是一个序列(可以为空)。
- Callback 就是 Observer,除了 Callback 少了onNext(T t)方法。Observer 中在onError(Throwable t)方法被调用后,会继而调用onCompleted(),然后 Observer 会包装好并发送出事件流(因为它能发送一个序列)。
- abstract void start(Callback callback)对应 Subscription subscribe(final Observer
public class ApiWrapper {
Api api;
public Observable<List<Student>> queryStudents(final String query) {
return Observable.create(new Observable.OnSubscribe<List<Student>>() {
@Override
public void call(final Subscriber<? super List<Student>> subscriber) {
api.queryStudents(query, new Api.QueryStudentCallBack() {
@Override
public void onCatListReceived(List<Student> students) {
subscriber.onNext(students);
}
@Override
public void onQueryError(Exception e) {
subscriber.onError(e);
}
});
}
});
}
public Observable<Uri> save(final Student student) {
return Observable.create(new Observable.OnSubscribe<Uri>() {
@Override
public void call(final Subscriber<? super Uri> subscriber) {
api.store(cat, new Api.SaveCallBack() {
@Override
public void onStudentSaved(Uri uri) {
subscriber.onNext(uri);
}
@Override
public void onSaveError(Exception e) {
subscriber.onError(e);
}
});
}
});
}
}
public class StudentHelper {
ApiWrapper apiWrapper;
public Observable<Uri> saveTheBestStudent(String query) {
Observable<List<Student>> studentsObservable = apiWrapper.queryStudents(query);
Observable<Student> bestStudentObservable = studentsObservable.map(new Func1<List<Student>, Student>() {
@Override
public Student call(List<Student> students) {
return StudentHelper.this.findBestStudent(students);
}
});
Observable<Uri> saveUriObservable = bestStudentObservable.flatMap(new Func1<Student, Observable<? extends Uri>>() {
@Override
public Observable<? extends Uri> call(Student student) {
return apiWrapper.save(student);
}
});
return storedUriObservable;
}
public Student findBestStudent(List<Student> students) {
return students.get(0);
}
}
这就是Rxjava的map方法和flatMap方法的演变由来,这还只是RxJava的一小部分东西,Rxjava的魅力和强大远不止这样,让我通过们不断的使用和学习来加强对它的理解和掌握吧!