1) 要使用這兩個框架當然要先把這兩個框架的包導(dǎo)進來:這里可以看到還導(dǎo)入了RxBinding 的包啃匿,這是為了使用防抖功能而導(dǎo)入的,同時因為是開發(fā) Android蛆楞,因此除了導(dǎo)入 RxJava 還需導(dǎo)入 RxAndroid溯乒,否則所需的 API 是不完整的,RxJava占所需代碼的 80%豹爹,RxAndroid 占20%裆悄,只有把這兩部分一起導(dǎo)入,才是我們完整的API臂聋,例如我們在切換線程時光稼,最經(jīng)常用到的 AndroidSchedulers.mainThread(),就是 RxAndroid包里的孩等。
// 依賴RxAndroid 2X 的依賴庫
// 增加RxJava 2X 的依賴庫
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.0.7'
// OkHttp相關(guān)
implementation 'com.facebook.stetho:stetho:1.4.2'
implementation 'com.facebook.stetho:stetho-okhttp3:1.4.2'
// 網(wǎng)絡(luò)請求相關(guān)
implementation "com.squareup.retrofit2:retrofit:2.4.0"
implementation "com.squareup.retrofit2:retrofit-mock:2.4.0"
implementation "com.squareup.retrofit2:converter-gson:2.8.2"
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
implementation "com.squareup.retrofit2:converter-scalars:2.4.0"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
implementation "com.squareup.retrofit2:converter-gson:2.8.2"
implementation "com.google.code.gson:gson:2.8.2"
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1' // 操作功能防抖
2)使用 Retrofit 請求網(wǎng)絡(luò)首先要寫網(wǎng)絡(luò)的請求接口艾君,以及給這個接口打上注解(包括請求方式,地址肄方,以及傳參等)注意這里返回的是一個 Observable(被觀察者)而我之前手寫 Retrofit 的文章里返回的是一個 okHttp 的 Call冰垄。
public interface WanAndroid {
//總數(shù)據(jù)
@GET("project/tree/json")
Observable<ProjectBean> getProject();
//Item數(shù)據(jù)
@GET("project/list/{pageIndex}/json")
Observable<ProjectItem>getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);
}
3)接下來就是對 Retrofit對象 構(gòu)建的封裝,因為 Retrofit 是通過 okHttp 請求網(wǎng)絡(luò)的扒秸,因此播演,這里其實也是對 okHttp 的封裝。最后還封裝了一個 RxJava 的線程切換方法伴奥,通過這個方法結(jié)合 compose 操作符就可以給上游分配到 io 異步線程写烤,下游分配到 Android 主線程:
//設(shè)置BaseUrl,這部發(fā)將拼接到上一步注解的前半部分
public static String BASE_URL = "https://www.wanandroid.com/";
public static void setBaseUrl(String baseUrl) {
BASE_URL = baseUrl;
}
/**
* 根據(jù)各種配置創(chuàng)建出Retrofit
*
* @return 返回創(chuàng)建好的Retrofit
*/
public static Retrofit getOnlineCookieRetrofit() {
// OKHttp客戶端
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
// 各種參數(shù)配置
OkHttpClient okHttpClient = httpBuilder
.addNetworkInterceptor(new StethoInterceptor())
.readTimeout(10000, TimeUnit.SECONDS)
.connectTimeout(10000, TimeUnit.SECONDS)
.writeTimeout(10000, TimeUnit.SECONDS)
.build();
return new Retrofit.Builder().baseUrl(BASE_URL)
// TODO 請求用 OKhttp
.client(okHttpClient)
// TODO 響應(yīng)RxJava
// 添加一個json解析的工具
.addConverterFactory(GsonConverterFactory.create(new Gson()))
// 添加rxjava處理工具
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
//線程切換封裝
public static <UD> ObservableTransformer<UD,UD> rxud(){
return new ObservableTransformer<UD, UD>() {
@Override
public ObservableSource<UD> apply(Observable<UD> upstream) {
//上游分配異步線程
return upstream.subscribeOn(Schedulers.io())
//下游分配主線程
.observeOn(AndroidSchedulers.mainThread())
.map(new Function<UD, UD>() {
@Override
public UD apply(UD ud) throws Exception {
Log.d("---", "apply: 我監(jiān)聽到你了拾徙,居然再執(zhí)行");
return ud;
}
});
}
};
}
4)當然還要定義返回數(shù)據(jù)的 bean 類洲炊,我這里定義了兩個 ProjectBean ,ProjectItem尼啡,就是一些基本的 set & get暂衡,這里省略不寫。
5)使用的時候跟使用 Retrofit 時一樣崖瞭,先獲得 第 2) 步 定義的接口對象狂巢,通過接口對象請求網(wǎng)絡(luò),通過 RxJava 操作返回的數(shù)據(jù):
//獲取全部數(shù)據(jù)
private void getProjectData() {
disposable = api.getProject()
.compose(HttpUtil.rxud())//切換線程
.subscribe(new Consumer<ProjectBean>() {
@Override
public void accept(ProjectBean projectBean) throws Exception {
Log.e("---", projectBean.toString());
}
});
}
可以看到這里使用了一個 Disposable 來接收操作完數(shù)據(jù)的結(jié)果书聚,Disposable 的提供一個中斷的作用唧领,可以利用這個變量進行中斷操作藻雌,當 APP 在關(guān)閉時,如果后臺仍然持有Context 對象繼續(xù)操作數(shù)據(jù)斩个,這就會引發(fā)內(nèi)存泄露胯杭,因此需要通過這個變量來防止內(nèi)存泄漏:在onDestory 中斷操作數(shù)據(jù)
@Override
protected void onDestroy() {
super.onDestroy();
if (disposable != null) {
if (!disposable.isDisposed()) {
disposable.dispose();
}
}
}
6)當出現(xiàn)網(wǎng)絡(luò)嵌套的情況,可以使用 flatMap 操作符解決受啥,flatMap 的作用是把數(shù)據(jù)處理完之后又封裝成一個被觀察者繼續(xù)傳給下游.做个。同時在這里使用了防抖(指的是指定時間內(nèi)允許用戶操作指定次數(shù)某控件):
//使用防抖+網(wǎng)絡(luò)嵌套問題
//這里第一次層級嘗試使用map操作符,但是效果不佳,查看map/flatMap源碼:
//public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)
//public final <R> Observable<R> map(Function<? super T, ? extends R> mapper)
//可以看到flatMap操作符的Function的第二個入?yún)?下游)是個被觀察者滚局,將這個被觀察者作為下一步操作的上游
//而map的第二個入?yún)⑹菦]有限制的泛型居暖,
//總結(jié):fltaMap 與 map 的區(qū)別是fltaMap 讓用戶操作完成之后又封裝成一個被觀察者繼續(xù)向下傳遞
private void getDataByView() {
Button btnNet = findViewById(R.id.btn_net);
disposable = RxView.clicks(btnNet)
.throttleFirst(2, TimeUnit.SECONDS)//2s-允許點擊一次
.observeOn(Schedulers.io())
.flatMap(
new Function<Object, ObservableSource<ProjectBean>>() {
@Override
public ObservableSource<ProjectBean> apply(Object o) throws Exception {
return api.getProject();
}
})
.flatMap(
new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {
@Override
public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
return Observable.fromIterable(projectBean.getData());
}
})
.flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
@Override
public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
return api.getProjectItem(1, dataBean.getId());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ProjectItem>() {
@Override
public void accept(ProjectItem projectItem) throws Exception {
}
});
}
7)map操作符:作用是將上游的數(shù)據(jù)傳再到下游觀察者之前進行一次操作,轉(zhuǎn)換成用戶所需要的類型后再傳給觀察者核畴,因此觀察者接收到的上游就是被 map 轉(zhuǎn)換之后的下游:
//獲取全部數(shù)據(jù)
private void getProjectMap() {
disposable = api.getProject()
.compose(HttpUtil.rxud())//切換線程
//注意這里上游是 ProjectBean膝但,提供給下游觀察者的是 String
.map(new Function<ProjectBean, String>() {
@Override //這里返回的 String 提供給下游觀察者
public String apply(ProjectBean projectBean) throws Exception {
return null;
}
})
//觀察者接收到 map 返回的 String
.subscribe(new Consumer<String>() {
@Override
public void accept(String str) throws Exception {
Log.e("---", str);
}
});
}
8)**doOnNext操作符:在觀察者的 next 操作之前先執(zhí)行這個方法冲九,一般用在一連續(xù)的操作(比如注冊后顯示UI谤草,緊接著跳轉(zhuǎn)登錄)map 是在上游傳給下游時進行一次攔截,而 doOnNext 則是在下游往上游回傳時進行攔截:
//doOnNext練習(xí)
//doOnNext:就是在拿到結(jié)果交給訂閱者之前截斷莺奸,處理完成后再交給訂閱者的Next操作
//map操作是在數(shù)據(jù)發(fā)送數(shù)據(jù)時丑孩,上游與下游之間截斷
//doOnNext 是在拿到數(shù)據(jù)后,下游往上游回傳時截斷
private void getDataByNext(){
disposable = api.getProject()
.compose(HttpUtil.rxud())
.doOnNext(new Consumer<ProjectBean>() {
@Override
public void accept(ProjectBean projectBean) throws Exception {
Log.e("---","先執(zhí)行這里");
}
})
.subscribe(new Consumer<ProjectBean>() {
@Override
public void accept(ProjectBean projectBean) throws Exception {
Log.e("---","后執(zhí)行這里");
}
});
}
本篇主要以使用為主灭贷,RxJava 的原理性將在下篇文章講解温学,希望對你有所幫助~