RxJava 出来很久了,以至于现在大红大紫。在 Android 平台中的影响更是不可言语,很多新开源项目中也纷纷引入了她。但我一直因为各种原因没有动手揭开她神秘的面纱。目前 Rx (ReactiveX) 对 Android 支持已经非常强大, 从数据库到业务逻辑异步处理,再到与 MVP 设计模式的结合都已经有相对成熟解决方案。现在正是入手的好时机。现在网络上有关于 RxJava 的文章很多,在此就不累赘她的好处和使用方法,感兴趣可以自行学习。
说明: 本人对 RxJava 的理解不是很深刻,目前只处于会用的阶段。部分观点可能会有误导
本文要解决的问题: 对 RxJava 技术体系在 Android 实际项目中具体使用的理解
RxJava 理解
使用 Thread 实现:
new Thread() {
@Override
public void run() {
super.run();
for (File folder : folders) {
File[] files = folder.listFiles();
for (File file : files) {
if (file.getName().endsWith(".png")) {
final Bitmap bitmap = getBitmapFromFile(file);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
imageCollectorView.addImage(bitmap);
}
});
}
}
}
}
}.start();
通过 RxJava 的使用:
Observable.from(folders)
.flatMap(new Func1<File, Observable<File>>() {
@Override
public Observable<File> call(File file) {
return Observable.from(file.listFiles());
}
})
.filter(new Func1<File, Boolean>() {
@Override
public Boolean call(File file) {
return file.getName().endsWith(".png");
}
})
.map(new Func1<File, Bitmap>() {
@Override
public Bitmap call(File file) {
return getBitmapFromFile(file);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) {
imageCollectorView.addImage(bitmap);
}
});
这里可以看出,使用 RxJava 能够很好的让代码逻辑变的简单。RxJava 的操作方式乍一看很像 Builder 模式,在创建类的时候先给类添加各种初始化参数,然后调用 Build 创建对象。然而 RxJava 每一步都有相应的动作(action),既都会对上一个动作返回的数据做出必要的处理,然后将变化的数据传递下去。subscribe() 方法在末尾调用,最终数据会在这里被使用。可以认为 subscribe() 被调用后,就会启动上面一连串动作(这样理解对于初学者就够)。
上面例子中用到的那些方法只要理解了,基本上 RxJava 就可以正常使用。有问题再查看官方文档。
关于rxjava的一些记录
Func1 和 Action1 的区别在于, Func1 包装的是有返回值的方法。另外,和 ActionX 一样, FuncX 也有多个,用于不同参数个数的方法。FuncX 和 ActionX的区别在 FuncX 包装的是有返回值的方法。
线程控制
Observable.just(1,2,3,4)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.map(doSomething) // 执行在 newThread 中
.observeOn(AndroidSchedulers.mainThread)
.subscribe(subscriber); // 执行在 UI 线程中
observeOn()指定的是 Subscriber的线程,而这个 Subscriber并不是subscribe()参数中的 Subscriber,而是 observeOn()执行时的当前 Observable所对应的 Subscriber ,即它的直接下级 Subscriber 。换句话说,observeOn()指定的是它之后的操作所在的线程
Sqlbrite
例子:
Observable<Query> users = db.createQuery("users", "SELECT * FROM users");
users.subscribe(new Action1<Query>() {
@Override public void call(Query query) {
Cursor cursor = query.run();
// TODO parse data...
}
});
因为作者的初衷并不是为了简化对 SQLite 的操作,也没有打算完全透明对 SQL 的使用。所以个人感觉不是很好用,我更乐意使用 GreenDao 。
Retrofit
一款现在很流行的网络请求地方库。使用起来很简单。
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder()
.build();
GitHubService service = retrofit.create(GitHubService.class);
另外关注以下几个关键字:
- @GET
- @Path
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
- @Query
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
- @QueryMap
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
- @Body
EventBus 与 RxJava 的选择
该库的设计初衷是在 Activities, Fragments, Threads, Services 等模块间轻松的建立链接。降低两个模块之间的耦合性,通过事件进行模块间通信。同时支持异步操作。
RxJava 被设计出来的初衷也是为了解决异步任务。并且通过流式编写,让一连串任务依次执行。虽然 RxJava 是通过观察者模式订阅事件。但如果抛开被观察者和观察者的概念,通过代码流式风格的编写来理解 RxJava 设计思想,似乎也是可以的。
问题又回到了原点,EventBus 和 RxJava 该如何选择呢?个人理解 RxJava 确实能从代码的角度清晰业务逻辑。事件的处理有事件序列来控制,能很清楚展示一个事件从开始处理到结束所经历的操作,并且可以根据需要控制事件在哪个 Thread 中被处理。当项目的业务很复杂的时候,我们会选择将业务逻辑进行隔离。业务内部使用 RxJava 处理,业务之间可以通过 EventBus 来进行消息传递。这样能使业务完全解耦。
RxJava 与 MVP
- 编写 Contract 接口存放 IView 接口和 Presenter 接口
public interface Contract {
interface View extends BaseView<Presenter> {
// 更新UI的操作接口
}
interface Presenter extends BasePresenter {
// 业务相关数据操作接口
}
}
public interface BasePresenter {
void subscribe();
void unsubscribe();
}
public interface BaseView<T> {
void setPresenter(T presenter);
}
- Fragment 实现 Contract.View 接口
- Custom Presenter 实现 Contract.BasePresenter 接口
- 在 Custom Presenter 使用 RxJava 编写业务逻辑