前言:
Retrofit前面有篇特別講解了:淺談Android網絡封裝框架Retrofit 這裏就不做過多的介紹了!
Retrofit 除了提供了傳統的 Callback 形式的 API,還有 RxJava 版本的 Observable 形式 API。下面我用對比的方式來介紹 Retrofit 的 RxJava 版 API 和傳統版本的區別。
以獲取一個 User 對象的接口作爲例子。使用Retrofit 的傳統 API,你可以用這樣的方式來定義請求:
@GET("/user")
public void getUser(@Query("userId") String userId, Callback<User> callback);
在程序的構建過程中, Retrofit 會把自動把方法實現並生成代碼,然後開發者就可以利用下面的方法來獲取特定用戶並處理響應:getUser(userId, new Callback<User>() {
@Override
public void success(User user) {
userView.setUser(user);
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
而使用 RxJava 形式的 API,定義同樣的請求是這樣的:@GET("/user")
public Observable<User> getUser(@Query("userId") String userId);
使用的時候是這樣的:getUser(userId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});
當 RxJava 形式的時候,Retrofit 把請求封裝進 Observable ,在請求結束後調用 onNext() 或在請求失敗後調用 onError()。
對比來看, Callback 形式和 Observable 形式長得不太一樣,但本質都差不多,而且在細節上 Observable 形式似乎還比 Callback 形式要差點。那 Retrofit 爲什麼還要提供 RxJava 的支持呢?
因爲它好用啊!從這個例子看不出來是因爲這只是最簡單的情況。而一旦情景複雜起來, Callback 形式馬上就會開始讓人頭疼。比如:
假設這麼一種情況:你的程序取到的 User 並不應該直接顯示,而是需要先與數據庫中的數據進行比對和修正後再顯示。使用 Callback 方式大概可以這麼寫:
getUser(userId, new Callback<User>() {
@Override
public void success(User user) {
processUser(user); // 嘗試修正 User 數據
userView.setUser(user);
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
很簡便,但不要這樣做。因爲這樣做會影響性能。數據庫的操作很重,一次讀寫操作花費 10~20ms 是很常見的,這樣的耗時很容易造成界面的卡頓。所以通常情況下,如果可以的話一定要避免在主線程中處理數據庫。所以爲了提升性能,這段代碼可以優化一下:
getUser(userId, new Callback<User>() {
@Override
public void success(User user) {
new Thread() {
@Override
public void run() {
processUser(user); // 嘗試修正 User 數據
runOnUiThread(new Runnable() { // 切回 UI 線程
@Override
public void run() {
userView.setUser(user);
}
});
}).start();
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
性能問題解決,但……這代碼實在是太亂了,迷之縮進啊!雜亂的代碼往往不僅僅是美觀問題,因爲代碼越亂往往就越難讀懂,而如果項目中充斥着雜亂的代碼,無疑會降低代碼的可讀性,造成團隊開發效率的降低和出錯率的升高。
這時候,如果用 RxJava 的形式,就好辦多了。 RxJava 形式的代碼是這樣的:
getUser(userId)
.doOnNext(new Action1<User>() {
@Override
public void call(User user) {
processUser(user);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});
後臺代碼和前臺代碼全都寫在一條鏈中,明顯清晰了很多。再舉一個例子:假設 /user 接口並不能直接訪問,而需要填入一個在線獲取的 token ,代碼應該怎麼寫?
Callback 方式,可以使用嵌套的 Callback:
@GET("/token")
public void getToken(Callback<String> callback);
@GET("/user")
public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);
..
getToken(new Callback<String>() {
@Override
public void success(String token) {
getUser(token, userId, new Callback<User>() {
@Override
public void success(User user) {
userView.setUser(user);
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
});
倒是沒有什麼性能問題,可是迷之縮進毀一生,你懂我也懂,做過大項目的人應該更懂。而使用 RxJava 的話,代碼是這樣的:
@GET("/token")
public Observable<String> getToken();
@GET("/user")
public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);
...
getToken()
.flatMap(new Func1<String, Observable<User>>() {
@Override
public Observable<User> onNext(String token) {
return getUser(token, userId);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});
用一個 flatMap() 就搞定了邏輯,依然是一條鏈!好,Retrofit 部分就到這裏。