首先介绍下观察者模式
假如你有一家报社 负责生产报纸 客人负责订阅报纸 生产完报纸就通知发报纸给客人阅读
这个时候如果你直接硬编码在报社的代码里加入了具体的某个订了报纸的客人(依赖实现)甚至他阅读报纸的业务 就造成了强耦合
导致报社还需要管客人阅读这件事 这显然是不可以的
观察者模式就是为了松耦合,在报社(被观察者)内部维护一个数据结构,管理当前有多少个客人的接口(订阅者),报纸一生产完毕就通知客人,将阅读的业务分割到客人里,报社只依赖订阅者这个接口,而不依赖于具体的实现(具体哪个客人)。
这样做到了报社(被观察者只负责生产和分发),只要客人各自实现订阅者的接口,并向报社注册,就可以在生产完报纸就被分发到,客人只负责阅读。
这样做到了生产和消费的解耦和,在android开发中,我们可以将网络请求试做生产,将更新UI视为消费。
这样生产消费解耦和,结合rxjava的map/flatmap操作符,就可以将原有的callback加handler方式的嵌套网络请求和切换到UI线程,从迷之嵌套变为链式操作 下面时代码示例
这里我用个不太优雅的举例
我用一个查图书馆的接口做示范
我的业务是 当用户查询java时不仅返回java的结果 还自动帮用户查了docker的结果并更新UI展示给用户
类似强行安利哈哈
这里网络请求图书信息相当于报社生产报纸 更新UI相当于收到发来的报纸后进行阅读
首先实例两个查图书的service
BookService bookService1 = RxRetrofit.getInstance().create(BookService.class);
final BookService bookService2 = RxRetrofit.getInstance().create(BookService.class);
先查下java这本书 1表示第一页 将生产(第一个网络请求)设置在IO线程
然后使用map操作符 先把返回的jsonbean里的内容更新到UI上 例如toast 上面的observeOn指定的就是map里面操作的线程 不能直接在下面的flatmap操作里打toast 这样会导致这个flatmap里的call不仅要网络请求 又要更新UI 出现线程问题
然后将这个bean再传给下一级 以备下一级请求需要
然而我这里没用
observeOn制定flatmap里的操作是在IO线程 因为我还要再进行一次网络请求
然后直接使用flatmap操作符 做链式网络请求 ,返回一个observable 即返回一个被观察者
相当于把上一级的消费结果当成下一级的生产,再查了一次docker的内容,最后切换到UI线程 订阅一下 在onnext方法里执行你最终要完成的事(例如读报纸)
bookService1.getBook("java", "1")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<LibraryBean, LibraryBean>() {
@Override
public LibraryBean call(LibraryBean libraryBean) {
Toast.makeText(context, libraryBean.getResponse().get(0).getTitle(), Toast.LENGTH_LONG).show();
Log.i("map", Thread.currentThread().toString());
return libraryBean;
}
})
.observeOn(Schedulers.io())
.flatMap(new Func1<LibraryBean, Observable<LibraryBean>>() {
@Override
public Observable<LibraryBean> call(LibraryBean bean) {
Log.i("flatmap",Thread.currentThread().toString());
Log.i("flatmap",bean.getResponse().get(0).getTitle());
return bookService2.getBook("docker", "1");
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<LibraryBean>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Log.i("subscribe", Thread.currentThread().toString());
Log.i("info", e.toString());
}
@Override
public void onNext(LibraryBean libraryBean) {
Log.i("subscribe", Thread.currentThread().toString());
Toast.makeText(context, libraryBean.getResponse().get(0).getTitle(), Toast.LENGTH_LONG).show();
}
});
flatmap不止可以用作嵌套网络请求 还可以用来分发一对多的请求
这里我定义了一个学生类 这个学生有多门课程
public class Student {
private List<String> courses=new ArrayList<>();
public List<String> getCourses() {
courses.add("java");
courses.add("php");
courses.add("python");
courses.add("ruby");
courses.add("docker");
return courses;
}
}
下面是使用flatmap,不使用for循环 就将学生对应的课程的图书信息查出来
首先先随便查一次hello 然后用flatmap平铺各个课程,返回对应各个课程泛型的被观察者,然后根据各个课程名字 嵌套请求除对应的信息
BookService bookService1 = RxRetrofit.getInstance().create(BookService.class);
final BookService bookService2 = RxRetrofit.getInstance().create(BookService.class);
bookService1.getBook("hello", "1")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<LibraryBean, Observable<String>>() {
@Override
public Observable<String> call(LibraryBean libraryBean) {
Toast.makeText(context, libraryBean.getResponse().get(0).getTitle(), Toast.LENGTH_LONG).show();
return Observable.from(new Student().getCourses());
}
})
.observeOn(Schedulers.io())
.flatMap(new Func1<String, Observable<LibraryBean>>() {
@Override
public Observable<LibraryBean> call(String s) {
return bookService2.getBook(s, "1");
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<LibraryBean>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(LibraryBean libraryBean) {
Toast.makeText(context, libraryBean.getResponse().get(0).getTitle(), Toast.LENGTH_LONG).show();
}
});
运行完毕后将会看到toast输出了hello的书目 然后依次输出 java php python ruby docker的书目
有了rxjava和retrofit 抛弃嵌套callback handler 就是区别你和突击培训班出来的三年安卓开发经验的程序员的途径了哈哈