天天看點

簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝

簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝

本人近期在看網絡請求架構封裝時,看到網上呼聲最高的是此類,輕便又簡潔,近日閑來無事,就為各位農友寫了個案例,摳腳來的不喜勿噴哦。

  • 簡單實作RxJava2OkhttpRetrofit2的網絡請求架構封裝
    • OKhttp
    • RxJava2
    • Retrofit
  • Retrofit2的配置以及使用
  • Okhttp的配置以及使用
  • RxJava2的配置以及使用
  • 對回掉的簡單封裝
簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝

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+Okhttp+Retrofit2的網絡請求架構封裝簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝

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簡介

簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝簡單實作RxJava2+Okhttp+Retrofit2的網絡請求架構封裝

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

繼續閱讀