一、RxJava
1,基本用法
創(chuàng)建 Observable、創(chuàng)建 Observer、 Subscribe
Observable一般用create(),也有just()、from()。
比如依次打印字符串?dāng)?shù)組 names 中的所有字符串:
String[] names = ...;
Observable.from(names)
.subscribe(new Action1<String>() {
@Override
public void call(String name) {
Log.d(tag, name);
}
});
2.線程控制Scheduler
在不指定線程的情況下, RxJava 遵循的是線程不變的原則,即:在哪個(gè)線程調(diào)用 subscribe(),就在哪個(gè)線程生產(chǎn)事件;在哪個(gè)線程生產(chǎn)事件,就在哪個(gè)線程消費(fèi)事件。如果需要切換線程,就需要用到 Scheduler。
Scheduler方法有immediate()、newThread()、io()、computation()??梢允褂?subscribeOn()(發(fā)生線程) 和 observeOn() (運(yùn)行線程)兩個(gè)方法來(lái)對(duì)線程進(jìn)行控制了。
比如:
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});
3.變換
將事件序列中的對(duì)象或整個(gè)序列進(jìn)行加工處理,轉(zhuǎn)換成不同的事件或事件序列。
主要有map() 、flatMap()
二、Retrofit
1.定義API接口:
public interface PhoneService {
@GET("/apistore/mobilenumber/mobilenumber")
Call<PhoneResult> getResult(@Header("apikey") String apikey, @Query("phone") String phone);
}
private static final String BASE_URL = "http://apis.baidu.com";
private static final String API_KEY = "8e13586b86e4b7f3758ba3bd6c9c9135";
private void query(){
//1.創(chuàng)建Retrofit對(duì)象
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())//解析方法
.baseUrl(BASE_URL)//主機(jī)地址
.build();
//2.創(chuàng)建訪問(wèn)API的請(qǐng)求
PhoneService service = retrofit.create(PhoneService.class);
Call<PhoneResult> call = service.getResult(API_KEY, phoneView.getText().toString());
//3.發(fā)送請(qǐng)求
call.enqueue(new Callback<PhoneResult>() {
@Override
public void onResponse(Call<PhoneResult> call, Response<PhoneResult> response) {
//4.處理結(jié)果
if (response.isSuccess()){
PhoneResult result = response.body();
if (result != null){
PhoneResult.RetDataEntity entity = result.getRetData();
}
}
}
@Override
public void onFailure(Call<PhoneResult> call, Throwable t) {
}
});
}
3.結(jié)合RxJava
public interface Api {
@GET
Observable<LoginResponse> login(@Body LoginRequest request);
@GET
Observable<RegisterResponse> register(@Body RegisterRequest request);
}
private static Retrofit create() {
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
builder.readTimeout(10, TimeUnit.SECONDS);
builder.connectTimeout(9, TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(interceptor);
}
return new Retrofit.Builder().baseUrl(ENDPOINT)
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
Api api = retrofit.create(Api.class);
api.login(request)
.subscribeOn(Schedulers.io()) //在IO線程進(jìn)行網(wǎng)絡(luò)請(qǐng)求
.observeOn(AndroidSchedulers.mainThread()) //回到主線程去處理請(qǐng)求結(jié)果
.subscribe(new Observer<LoginResponse>() {
@Override
public void onSubscribe(Disposable d) {}
@Override
public void onNext(LoginResponse value) {}
@Override
public void onError(Throwable e) {
Toast.makeText(mContext, "登錄失敗", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete() {
Toast.makeText(mContext, "登錄成功", Toast.LENGTH_SHORT).show();
}
});
三、RxBinding
比如點(diǎn)擊監(jiān)聽(tīng):
Button button = ...;
RxView.clickEvents(button) // 以 Observable 形式來(lái)反饋點(diǎn)擊事件
.subscribe(new Action1<ViewClickEvent>() {
@Override
public void call(ViewClickEvent event) {
// Click handling
}
});
RxView.clickEvents(button)
.throttleFirst(500, TimeUnit.MILLISECONDS)
.subscribe(clickAction);
示例:RxJava + Retrofit + okHttp
一,Retrofit 寫(xiě)一個(gè)網(wǎng)絡(luò)請(qǐng)求
以獲取豆瓣 Top250 榜單為例,地址:https://api.douban.com/v2/movie/
1,首先,要使用Retrofit ,你肯定需要把它的包引入,在你的build.gradle文件中添加如下配置:
compile 'com.squareup.retrofit2:retrofit:2.1.0'//retrofit
compile 'com.google.code.gson:gson:2.6.2'//Gson 庫(kù)
//下面兩個(gè)是RxJava 和RxAndroid
compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'//轉(zhuǎn)換器,請(qǐng)求結(jié)果轉(zhuǎn)換成Model
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'//配合Rxjava 使用
2,創(chuàng)建一個(gè)Retrofit 實(shí)例,并且完成相關(guān)的配置
public static final String BASE_URL = "https://api.douban.com/v2/movie/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
說(shuō)明:配置了接口的baseUrl和一個(gè)converter,GsonConverterFactory 是默認(rèn)提供的Gson 轉(zhuǎn)換器,Retrofit 也支持其他的一些轉(zhuǎn)換器,詳情請(qǐng)看官網(wǎng)Retrofit官網(wǎng)
3,創(chuàng)建一個(gè) 接口 ,代碼如下:
public interface MovieService {
//獲取豆瓣Top250 榜單
@GET("top250")
Call<MovieSubject> getTop250(@Query("start") int start,@Query("count")int count);
}
說(shuō)明:定義了一個(gè)方法getTop250,使用get請(qǐng)求方式,加上@GET 標(biāo)簽,標(biāo)簽后面是這個(gè)接口的 尾址top250,完整的地址應(yīng)該是 baseUrl+尾址 ,參數(shù) 使用@Query標(biāo)簽,如果參數(shù)多的話可以用@QueryMap標(biāo)簽,接收一個(gè)Map
4,用Retrofit 創(chuàng)建 接口實(shí)例 MoiveService,并且調(diào)用接口中的方法進(jìn)行網(wǎng)絡(luò)請(qǐng)求,代碼如下:
//獲取接口實(shí)例
MovieService MovieService movieService = retrofit.create(MovieService.class);
//調(diào)用方法得到一個(gè)Call
Call<MovieSubject> call = movieService.getTop250(0,20);
//進(jìn)行網(wǎng)絡(luò)請(qǐng)求
call.enqueue(new Callback<MovieSubject>() {
@Override
public void onResponse(Call<MovieSubject> call, Response<MovieSubject> response) {
mMovieAdapter.setMovies(response.body().subjects);
mMovieAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<MovieSubject> call, Throwable t) {
t.printStackTrace();
}
});
以上是異步方式請(qǐng)求,還有同步方式execute(),返回一個(gè)Response,代碼如下:
Response<MovieSubject> response = call.execute();
以上就是用Retrofit 完成了一個(gè)網(wǎng)絡(luò)請(qǐng)求,獲取豆瓣top250 榜單電影。
以上示例是用get方式完成,如果要使用post 方式,我們只需要修改一下接口中的方法定義,如下:
public interface MovieService {
//獲取豆瓣Top250 榜單
@FormUrlEncoded
@POST("top250")
Call<MovieSubject> getTop250(@Field("start") int start, @Field("count") int count);
}
說(shuō)明:使用POST 請(qǐng)求方式時(shí),只需要更改方法定義的標(biāo)簽,用@POST 標(biāo)簽,參數(shù)標(biāo)簽用 @Field 或者@Body或者FieldMap,注意:使用POST 方式時(shí)注意2點(diǎn),1,必須加上 @FormUrlEncoded標(biāo)簽,否則會(huì)拋異常。2,使用POST方式時(shí),必須要有參數(shù),否則會(huì)拋異常, 源碼拋異常的地方如下:
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
以上就是一個(gè)使用Retrofit 完成一個(gè)網(wǎng)絡(luò)請(qǐng)求的完整示例,其他標(biāo)簽使用方式請(qǐng)看官網(wǎng)Retrofit官網(wǎng),官網(wǎng)用法也介紹的比較詳細(xì),此外,發(fā)現(xiàn)了一篇博客也介紹得比較詳細(xì),Retrofit用法詳解
二,配合RxJava 使用
1, 更改定義的接口,返回值不再是一個(gè)Call ,而是返回的一個(gè)Observble.
public interface MovieService {
//獲取豆瓣Top250 榜單
@GET("top250")
Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
}
2,創(chuàng)建Retrofit 的時(shí)候添加如下代碼
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
3,添加轉(zhuǎn)換器Converter(將json 轉(zhuǎn)為JavaBean)
addConverterFactory(GsonConverterFactory.create())
4,Activity 或者 Fragment 中傳入 Subscriber 建立訂閱關(guān)系
Subscription subscription = movieService.getTop250(0,20)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<MovieSubject>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(MovieSubject movieSubject) {
mMovieAdapter.setMovies(movieSubject.subjects);
mMovieAdapter.notifyDataSetChanged();
}
});
以上是加入RxJava 后的網(wǎng)絡(luò)請(qǐng)求,返回不再是一個(gè)Call ,而是一個(gè)Observable, 在Activity / Fragment 中傳入一個(gè)Subscriber 建立訂閱關(guān)系,就可以在 onNext 中處理結(jié)果了,RxJava 的好處是幫我處理線程之間的切換,我們可以在指定訂閱的在哪個(gè)線程,觀察在哪個(gè)線程。我們可以通過(guò)操作符進(jìn)行數(shù)據(jù)變換。整個(gè)過(guò)程都是鏈?zhǔn)降?,?jiǎn)化邏輯。其中FlatMap 操作符 還可以解除多層嵌套的問(wèn)題??傊?,RxJava 很強(qiáng)大,能幫我處理很多復(fù)雜的場(chǎng)景,如果熟練使用的話,那么能提升我們的開(kāi)發(fā)效率。這里不打算講RxJava 的內(nèi)容,如果還不了解RxJava ,或者還對(duì)RxJava不熟悉的話,推薦幾篇寫(xiě)很優(yōu)秀的博客。
1,RxJava 的經(jīng)典文章,扔物線的 給 Android 開(kāi)發(fā)者的 RxJava 詳解
3,關(guān)于RxJava 友好的文章-進(jìn)階
三,加入 OkHttp 配置
通過(guò)OkHttpClient 可以配置很多東西,比如鏈接超時(shí)時(shí)間,緩存,攔截器等等。代碼如下:
// 創(chuàng)建 OKHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//連接超時(shí)時(shí)間
builder.writeTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//寫(xiě)操作 超時(shí)時(shí)間
builder.readTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//讀操作超時(shí)時(shí)間
// 添加公共參數(shù)攔截器
BasicParamsInterceptor basicParamsInterceptor = new BasicParamsInterceptor.Builder()
.addHeaderParam("userName","")//添加公共參數(shù)
.addHeaderParam("device","")
.build();
builder.addInterceptor(basicParamsInterceptor);
// 創(chuàng)建Retrofit
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.build();
以上只是配置了一些簡(jiǎn)單的項(xiàng),如,連接超時(shí)時(shí)間,實(shí)際項(xiàng)目中,我們可能有一些公共的參數(shù),如 ,設(shè)備信息,渠道,Token 之類的,每個(gè)接口都需要用,我們可以寫(xiě)一個(gè)攔截器,然后配置到OKHttpClient里,通過(guò) builder.addInterceptor(basicParamsInterceptor) 添加,這樣我們就不用每個(gè)接口都添加這些參數(shù)了。緩存也可以通過(guò)寫(xiě)一個(gè)攔截器來(lái)實(shí)現(xiàn)(后面文章再講)。
以上就是Retrofit+RxJava+OkHttp實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的簡(jiǎn)單演示,如果每個(gè)接口都這么寫(xiě)的話,代碼量太多,而且不優(yōu)雅。所以還需要我們封裝一下,由于篇幅有限,封裝放到下一篇文章。
** Retrofit + RxJava + OkHttp 封裝已更新,請(qǐng)看Retrofit + RxJava + OkHttp 讓網(wǎng)絡(luò)請(qǐng)求變的簡(jiǎn)單-封裝篇**
參考博客:
2,基于Retrofit、OkHttp、Gson封裝通用網(wǎng)絡(luò)框架
3, RxJava 與 Retrofit 結(jié)合的最佳實(shí)踐
作者:依然范特稀西
鏈接:http://m.itdecent.cn/p/5bc866b9cbb9
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。</pre>