RxJava 出來很久了,以至于現在大紅大紫。在 Android 平臺中的影響更是不可言語,很多新開源項目中也紛紛引入了她。但我一直因為各種原因沒有動手揭開她神秘的面紗。目前 Rx (ReactiveX) 對 Android 支持已經非常強大, 從數據庫到業務邏輯異步處理,再到與 MVP 設計模式的結合都已經有相對成熟解決方案?,F在正是入手的好時機?,F在網絡上有關于 RxJava 的文章很多,在此就不累贅她的好處和使用方法,感興趣可以自行學習。
說明: 本人對 RxJava 的理解不是很深刻,目前只處于會用的階段。部分觀點可能會有誤導
本文要解決的問題: 對 RxJava 技術體系在 Android 實際項目中具體使用的理解
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() 方法在末尾調用,最終數據會在這里被使用??梢哉J為 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
簡介:A lightweight wrapper around SQLiteOpenHelper which introduces reactive stream semantics to SQL operations。個人覺得這是為了讓 SQLite 能和 RxJava 結合起來才有的庫
github 地址: 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()
.baseUrl("https://api.github.com/")
.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
更多 API 用法可以查閱官方文檔 DOC ,也可搭配學習RxJava 與 Retrofit 結合的最佳實踐
EventBus 與 RxJava 的選擇
EventBus 官方介紹為:Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality. Detail
該庫的設計初衷是在 Activities, Fragments, Threads, Services 等模塊間輕松的建立鏈接。降低兩個模塊之間的耦合性,通過事件進行模塊間通信。同時支持異步操作。
RxJava 被設計出來的初衷也是為了解決異步任務。并且通過流式編寫,讓一連串任務依次執行。雖然 RxJava 是通過觀察者模式訂閱事件。但如果拋開被觀察者和觀察者的概念,通過代碼流式風格的編寫來理解 RxJava 設計思想,似乎也是可以的。
問題又回到了原點,EventBus 和 RxJava 該如何選擇呢?個人理解 RxJava 確實能從代碼的角度清晰業務邏輯。事件的處理有事件序列來控制,能很清楚展示一個事件從開始處理到結束所經歷的操作,并且可以根據需要控制事件在哪個 Thread 中被處理。當項目的業務很復雜的時候,我們會選擇將業務邏輯進行隔離。業務內部使用 RxJava 處理,業務之間可以通過 EventBus 來進行消息傳遞。這樣能使業務完全解耦。
RxJava 與 MVP
MVP 可以良好的將視圖層和數據層通過 Presenter 進行隔離。Google 開發者也給出了 MVP 相關的設計方案 android-architecture 可以從基本的 MVP 開始學習,然后過度到與 RxJava 集合。
大體思路是:
- 編寫 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 編寫業務邏輯