RxJava和Retrofit的簡單使用
在最近做的專案中,因為頻繁用到網路請求,所以使用了現在比較流行的框架RxJava和Retrofit來代替之前的Okhttp的繁瑣請求。
我這邊寫的比較簡單,自己在小專案中更使用的,如果需要深入研究,進行一些封裝的,管理RxJava生命週期的,請移步http://p.codekk.com/detail/Android/RuffianZhong/Rx-Mvp。
retrofit是用來做網路請求操作,RxJava是用來切換執行緒、轉換資料操作的。
首先第一步,使用三方的框架,肯定是先新增依賴包。專案中用的Rxjava2.0、retrofit2.0,而且Rxjava2.0和Rxjava1.0並不相容,所以使用起來需要注意。新增一下依賴。
compile "com.squareup.retrofit2:retrofit:$rootProject.versions.libRetrofit"
compile "com.squareup.retrofit2:converter-gson:$rootProject.versions.libRetrofit"
compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.versions.libRetrofit"
compile "com.squareup.okhttp3:okhttp:$rootProject.versions.libOkhttp"
compile "com.squareup.okhttp3:logging-interceptor:$rootProject.versions.libOkhttp"
compile "io.reactivex.rxjava2:rxjava:$rootProject.versions.libRxJava"
compile "io.reactivex.rxjava2:rxandroid:$rootProject.versions.libRxAndroid"
第二步,建立一個Api例項 用來獲取介面的請求物件 在init()方法中通過baseUrl或得到Retrofit物件, 請求方法等都是放在介面中,介面與retrofit關聯在getNetDemo()方法中實現。
public class NetDemoApi {
private static NetDemoApi nInstance = new NetDemoApi();
private Retrofit mRequestDemo;
//baseUrl是每一個網路請求的前段,但必須是以 “/”結尾
private String mRequestDemoBaseUrl = "www.baidu.com/";
public static NetDemoApi getInstance(){
return nInstance;
}
private NetDemoApi(){
init();
}
private void init() {
//這一步就把baseurl和Retrofit關聯了起來,生成Retrofit物件
mRequestDemo = configure(mRequestDemoBaseUrl);
}
private NetDemo getNetDemo(){
return mRequestDemo.create(NetDemo.class);
}
//配置retrofit
private Retrofit configure(String baseUrl){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
WLog.i(message);
}
});
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
//這隻網路請求的攔截器 如果需要獲取到響應頭等相應資訊,在此處就可以獲得 如果不需要可以不寫
builder.networkInterceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
Headers headers = response.headers();
List<String> cookies = headers.values("Set-Cookie");
Session session = Session.getInstance();
session.setCookies(Utils.getCookie(cookies));
Log.d(getClass().getSimpleName(),"設定cookie " + session.getCookies());
return response;
}
});
builder.addInterceptor(logging);
builder.connectTimeout(30, TimeUnit.SECONDS);
builder.readTimeout(40, TimeUnit.SECONDS);
OkHttpClient client = builder.build();
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
//這是rxjava的轉換器,這個是rxjava2的預設介面卡工廠,如果我們需要轉換成bean,可以新增gson的轉換器,直接新增就可以,需要新增依賴包
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
}
第三步,寫實現的介面,這個介面中,才是我們需要請求的路徑
如下 @get 就是一個get請求的方法, @post就是一個post請求
@url 是直接傳入一個已知的URl進去,直接請求Url,而且跟baseUrl無關,不會跟baseUrl進行拼接;
@Query 就是在URl後面進行鍵值對的拼接,如下 tip傳入1 ,就會把 tip=1 拼接到loginicon=true的後面,get和post請求都是這樣拼接。
@Path 就是把傳入的字串直接傳入註解中{uuid}中的位置處;
@body 是post請求時,傳入的requestBody物件;
@Header 可以給網路請求新增請求頭資訊,新增Cookie就寫cookie,@Header("Cookie") String cookie,
以上傳入的url引數都會和baseUrl進行拼接,得到一個完整的Url去進行網路請求(除了@url)。
返回的就是Observable物件,我們呼叫此方法後,獲得observable物件,接下來用Rxjava進行資料解析,篩選。
public interface NetDemo {
@GET
Observable<ResponseBody> requestDemo(@url String url);
@GET("cgi-bin/mmwebwx-bin/login?loginicon=true")
Observable<ResponseBody> requestScanResult(@Query("tip") int tip,
@Query("uuid") String uuid,
@Query("r") String r,
@Query("_") String p);
@POST("qrcode/{uuid}")
Observable<ResponseBody> requestGenQRCode(@Path("uuid") String uuid,
@Body RequestBody body);
@POST("cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN")
public Observable<ResponseBody> webwxstatusnotify(@Query("pass_ticket") String passTicket,
@Header("Cookie") String cookie,
@Body RequestBody body);
}
第四步,在程式碼中進行網路請求,
Observable<ResponseBody> observable = WeChatNetApi.getInstance().getLoginInfo().requestLoginInfo(url); //返回Observable物件
observable.subscribeOn(Schedulers.io()) //進行網路請求是在那個執行緒 io 就是在子執行緒
.map(new Function<ResponseBody, Bitmap>() { //可以通過map進行轉換,把結果轉換為一個我們需要使用的型別(如demo,返回一個bitmap型別)
@Override
public Bitmap apply(@io.reactivex.annotations.NonNull
ResponseBody responseBody) {
return BitmapFactory.decodeStream(responseBody.byteStream());
}
})
.flatMap(new Function<String, ObservableSource<Bitmap>>() { //還可以通過flatMap轉化為Observable物件,轉換為Observable物件後,還可以繼續進行轉換操作,直到我們需要的型別
@Override
public ObservableSource<Bitmap> apply(
@io.reactivex.annotations.NonNull String uuid) {
return genQRCode(uuid);
}
}
.filter(new Func1<Community, Boolean>() { //只有返回true,才會繼續向下走,如果返回是false,就不會繼續向下走
@Override
public Boolean call(Community community) {
return community.houses.size()>10;
}
})
.observeOn(AndroidSchedulers.mainThread()) //網路請求結束,切換回主執行緒,進行資料處理,或者顯示的操作
.subscribe(new Observer<ResponseBody>() { //轉換結束,得到了我們需要的資料,進行顯示,先切換到主執行緒
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBody body) { //訂閱後subscribe會執行的方法
messageActivity.returnTextInfo(asJsonObject, l);
}
@Override
public void onError(Throwable e) { //如果流程中有報錯,會走到此
}
@Override
public void onComplete() { //onNext之後,如果還有後續的動作,可以在此繼續,onnext後會呼叫complete;
}
});
.doOnNext(new Consumer<ResponseBody>() { //doOnNext 直接訂閱是一個偷懶的寫法,這樣寫程式碼比較簡潔,而且這一步操作完之後,我也不需要繼續任何操作
@Override
public void accept(@io.reactivex.annotations.NonNull ResponseBody body) throws Exception {
handleLoginInfoResponse(url,body);
}
}).subscribe();