簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝
本人近期在看網絡請求架構封裝時,看到網上呼聲最高的是此類,輕便又簡潔,近日閑來無事,就為各位農友寫了個案例,摳腳來的不喜勿噴哦。
- 簡單實作RxJava2OkhttpRetrofit2的網絡請求架構封裝
- OKhttp
- RxJava2
- Retrofit
- Retrofit2的配置以及使用
- Okhttp的配置以及使用
- RxJava2的配置以及使用
- 對回掉的簡單封裝
OKhttp
OKhttp 相信各位農友都比較熟悉,它是一款高效的HTTP用戶端,支援連接配接同一位址的連結共享同一個socket,通過連接配接池來減小響應延遲,還有透明的GZIP壓縮,請求緩存等優勢 Okhttp官網
- Okhttp的配置
這裡我是使用的gson作為ConverterFactory,你也可以使用其他的,并且自己寫一個類實作下factory,我并沒有這樣操作。在這裡提醒下,有些背景傳回的資料格式并不是json格式,而是string格式,這裡我介紹下對string格式傳回值的支援 scalars,下面會見到配置
//okhttp的包
compile 'com.squareup.okhttp3:okhttp:3.9.0'
//retrofit對gson的支援
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
//請求字元串
compile 'com.squareup.retrofit2:converter-scalars:2.0.0'
- Okhttp的使用
建立一個對網絡的管理類HttpManager,裡面可以封裝網絡請求的baseurl,以及對okhttp的初始化
不同需求的okhttpclient可以多封裝幾個方法('詳細代碼後面會貼出')
'private OkHttpClient.Builder initOkhttpClien(){
//日志顯示級别
OkHttpClient.Builder httpclient=new OkHttpClient().newBuilder();
httpclient.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
//添加 token 過期攔截,和日志列印,這裡我寫了個攔截器,這裡可以對token重新整理進行一些操作,具體看業務需要
httpclient.addInterceptor(new TokenInterceptor());
return httpclient;
}'
詳細的okhttp使用以及源碼講解可以跳轉Okhttp詳解
RxJava2
ReactiveX 是一個專注于異步程式設計與控制可觀察資料(或者事件)流的API。它組合了觀察者模式,疊代器模式和函數式程式設計的優秀思想。實時資料處理是一件普通的現象,有一個高效、幹淨和可擴充的方式來處理這些情景是重要的。使用 Observables 和 Operators 來熟練操作它們。ReactiveX 提供一個可組合又靈活的 API 來建立和處理資料流,同時簡化了異步程式設計帶來的一些擔憂,如:線程建立和并發問題。
簡單點來說:就是一個觀察者通過訂閱被觀察者,依據被觀察者的一些變化做出相應的動作,觀察者可以改變被觀察者的生活狀态
- RxJava2的配置
這裡我使用的是rxjava2,是以導入的包也是對應rxjava2的
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
擴充卡 在前面加了,這裡就不重複了
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
- RxJava2的使用
這裡我寫一個簡單的例子:有三個學生,他們每個人有多種課程,我想列印每一個人的課程名都有哪些
**這裡是為了示範使用,例子并沒有實際意義**
public void testRx(){
List<Student> list=new ArrayList<>();
Student student=new Student();
List<Scort> scos=new ArrayList<>();
for (int i = ; i < ; i++) {
Scort sc=new Scort();
sc.setName("name1"+i);
scos.add(sc);
}
student.setName("zhs1");
student.setScorts(scos);
Student student2=new Student();
List<Scort> scos2=new ArrayList<>();
for (int j = ; j < ; j++) {
Scort sc=new Scort();
sc.setName("name2"+j);
scos2.add(sc);
}
student2.setName("zhs2");
student2.setScorts(scos2);
Student student3=new Student();
List<Scort> scos3=new ArrayList<>();
for (int h = ; h < ; h++) {
Scort sc=new Scort();
sc.setName("name"+h);
scos3.add(sc);
}
student3.setName("zhs3");
student3.setScorts(scos3);
list.add(student);
list.add(student2);
list.add(student3);
Consumer與的與Action1類似
Consumer<Scort> consumer=new Consumer<Scort>() {
@Override
public void accept(Scort scort) throws Exception {
System.out.println("課程名 "+scort.getName());
}
};
//背壓的封裝,具體可以看2.0介紹
//不需要for循環get等一堆操作既可以列印,簡介明了
Flowable.fromIterable(list).flatMap(new Function<Student, Publisher<Scort>>() {
@Override
public Publisher<Scort> apply(Student student) throws Exception {
return Flowable.fromIterable(student.getScorts());
}
}).subscribe(consumer);
}
代碼中Rxjava的展現在于 BaseObserver以及RxSchedulers;
後面會見到他們的使用
一個是對Observer的封裝,一個是對全局的請求攔截的配置;
如果你不知道Observer是幹什麼的,建議去看看Rxjava的介紹
public abstract class BaseObserver<T> implements Observer<BaseBean<T>> {
private Context mContext;
private ProgressDialog progressDialog;
private Disposable disposable;
//預設無效果的請求
protected BaseObserver(Context context){
this.mContext=context.getApplicationContext();
}
//帶進度條的請求
protected BaseObserver(Context context,boolean showProgress){
this.mContext=context.getApplicationContext();
if(showProgress){
progressDialog=new ProgressDialog(context);
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
disposable.dispose();
}
});
}
}
@Override
public void onSubscribe(Disposable d) {
disposable=d;
}
@Override
public void onNext(BaseBean<T> value) {
//這裡對資料bean的封裝,這裡看個人的網絡回掉的結果來操作,我是随便寫的
if (value.getTotal()>) {
T t = value.getSubject();
onHandleSuccess(t);
} else {
onHandleError(value.getTitle());
}
}
@Override
public void onError(Throwable e) {
if(progressDialog!=null){
progressDialog.dismiss();
}
}
@Override
public void onComplete() {
if(progressDialog!=null&&progressDialog.isShowing()){
progressDialog.dismiss();
}
}
protected abstract void onHandleSuccess(T t);
protected void onHandleError(String msg) {
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
}
/**
* 設定同一的攔截,對每個訂閱做相同的标準
*/
public class RxSchedulers {
public static <T> ObservableTransformer<T, T> compose(final Context context) {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> observable) {
return observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
if(!NetUtils.isNetworkConnected(context)){
Toast.makeText(context,"網絡異常",Toast.LENGTH_SHORT).show();
}
}
})
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}
也可以換一種寫法(看個人喜好)
public class BaseObservableTransFormer<T> implements ObservableTransformer<T,T>{
private Context context;
public BaseObservableTransFormer(Context context){
this.context=context;
}
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
//判斷網絡
if(!NetUtils.isNetworkConnected(context)){
Toast.makeText(context,"網絡異常",Toast.LENGTH_SHORT).show();
}
}
})
.observeOn(AndroidSchedulers.mainThread());
}
}
推薦一個Rxjava的入門簡介Rxjava簡介
Retrofit
簡單的說Retrofit将通路方式分成了三步,1.request的type設定;2.參數的配置,3.對response的回掉處理;
其實volley也是這樣,隻不過retrofit将更多的事情放到了對callback的處理,是以讓他做到了像一個方法請求了api似S的效果;
- Retrofit的配置
這裡我使用的是rxjava2,是以導入的包也是對應rxjava2的,如果你還是使用rxjava1,可以設定rxjava1的包,此包對1也相容
//retrofit的包
compile 'com.squareup.retrofit2:retrofit:2.3.0'
//對gson的支援
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
//對rxjava的适配
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
- Retrofit的使用
建立一個請求的接口類
//此處封裝的是Observable,Rxjava中的被觀察者
public interface ApiRequest {
@GET("top250")
Observable<BaseBean<List<Subject>>> getMovie(@Query("start") int start, @Query("count") int count);
//這個BaseBean是我對資料的封裝,像背景傳回給我們的資料都是具有一定的格式,我們以此可以做一些操作
...類似更多的接口都解除安裝這個類中
}
配置Retrofit的全局使用
//同樣,我們在配置okhttp的HttpManager類中初始化這個配置,這裡使用簡單的單例模式
SingleHolder寫在HttpManager類中
private static class SingleHolder{
private static HttpManager httpManager=null;
public static HttpManager getInstance(Context context){
if(httpManager==null){
httpManager=new HttpManager(context);
}
return httpManager;
}
}
//對Retrofit的初始化
private HttpManager(Context context){
this.mContext=context;
retrofit=new Retrofit.Builder()
//對okgttp的初始化
.client(initOkhttpClien().build())
//基礎的網絡請求域名
.baseUrl(baseUrl)
//對傳回字元串的支援,注意這個要寫在gson之前
.addConverterFactory(ScalarsConverterFactory.create())
//對gson的支援
.addConverterFactory( GsonConverterFactory.create())
//對rxjava的支援
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//接口方法類的反射擷取
request = retrofit.create(ApiRequest.class);
}
//簡單的單例模式
public static HttpManager init(Context context){
return SingleHolder.getInstance(context);
}
3.使用rxjava來傳回響應體
//這個方法也是寫在HttpManager中,對應的在ApiRequest 寫一個方法,這裡就寫一個
public void getMovie(int strat, int count, BaseObserver<List<Subject>> subscriber){
request.getMovie(strat,count).compose(RxSchedulers.<BaseBean<List<Subject>>>compose(mContext)).subscribe( subscriber);
}
4.在代碼中的使用
HttpManager.init(this).getMovie(, , new BaseObserver<List<Subject>>(this) {
//對網絡判斷的封裝放在RxSchedulers中,對傳回值code判斷放在BaseObserver中
@Override
protected void onHandleSuccess(List<Subject> subjects) {
System.out.println(subjects.get().toString());
}
});
項目位址 https://gitee.com/nimodou/RetrofitRxjava.git