1. 程式人生 > >Novate:Retrofit2.0和RxJava的又一次完美改進加強(Tamic部落格 -CSDN)

Novate:Retrofit2.0和RxJava的又一次完美改進加強(Tamic部落格 -CSDN)

作者/Tamic

這裡寫圖片描述

前言

用過RxJava和Retrofit的朋友,用久了就會發現Retrofit說難不難,說簡不簡,對於實際專案中,單純的用Retrofit做請求庫,開發起來還是很多不便,必須請求頭和引數處理,API介面數目眾多時的處理, Https證書驗籤,cookie持久,錯誤結果處理,統一操作載入過渡UI等,因此我對Retrofit再次進行了封裝,一直關注我的朋友以前看我封裝的《 基於Retrofit2.0 封裝的超好用的RetrofitClient工具類》的一文,已對Retrofit結合RxJava時遇到上面的問題進行了完整封裝,但是不是Builder模式,因此感覺還是有點土,特此我進行了長達兩個月Novate

框架的開發,

為何起名為Novate

Novate的英文原意是用新事物代替 ,我開發目的是用新的東西來代替Retrofit的有些不易操作的地方,因此起名新奇的東西,所以結合了原來的Http用法習慣,又加入了Retrofit和RxJava的特性,因此起名 :Novate

進行下文前請先了解Retrofit和Rxjava,不懂請移步:

系列導讀

介紹

Novate的改進

  • 優化設計:加入基礎API,減少Api冗餘
  • 強大的快取模式: 支援離線快取, 無網路智慧載入快取,可配置是否需要快取
  • cookie管理:自帶cookie管理機制
  • 全方位請求模式:支援多種方式訪問網路(get,put, post ,delete)
  • 輕送呼叫:支援表單,圖文一起,json上傳。
  • 檔案傳輸:支援檔案下載和上傳,支援進度
  • 動態新增:支援請求頭和引數統一新增,分別新增。
  • 結果處理:支援對返回結果的統一處理,自動幫你序列化複雜的資料。
  • 擴充套件性強:支援自定義的Retrofit的API,預設Api無法滿足時可自定義自己的Service
  • 悠雅方便:支援統一請求網路的過程的流程控制,以方便幫你完美加入Processbar進度。
  • RxJava結合: 結合RxJava,執行緒智慧控制。

效果

效果

用法

基本構建:

 Novate novate = new Novate.Builder(this)
            .baseUrl(baseUrl)
            .build();

除了基本的構建還提供更了其他API

 構建你的header頭和引數
 Map<String, String> headers = new HashMap<>();
  headers.put("apikey", "4545sdsddfd7sds");

 Map<String, String> parameters = new HashMap<>();
  parameters.put("uid", "878787878sdsd");

例項化:

  Novate novate = new Novate.Builder(this)
            .addParameters(parameters)
            .connectTimeout(8)
            .baseUrl("you api url")
            .addHeader(headers)
            .addLog(true)
            .build(); 

更多:

novate = new Novate.Builder(this)
                .addHeader(headers) //新增公共請求頭
                .addParameters(parameters)//公共引數
                .connectTimeout(10)  //連線時間 可以忽略
                .readTimeout(10)  //讀取 可以忽略
                .addCookie(false)  //是否同步cooike 預設不同步
                .addCache(true)  //是否快取 預設快取
                .addCache(cache, cacheTime)   //自定義快取
                .baseUrl("Url") //base URL
                .addLog(true) //是否開啟log
                .cookieManager(new NovateCookieManager()) // 自定義cooike,可以忽略
                .addInterceptor() // 自定義Interceptor
                .addNetworkInterceptor() // 自定義NetworkInterceptor
                .proxy(proxy) // 設定代理
                .client(client)  //clent 預設不需要
                .build(); 

如果你支援https需要接入證書:

      novate.addSSL(hosts,  certificates)

怎麼用?

準備證書檔案陣列和host 白名單;

 int[] certificates = {R.raw.myssl1, R.raw.myssl2,......}

 int[] hosts = {"https:// you hosturl2", "https:// you hosturl2",......}

還要說明?

certificates是你的ssl證書檔案的id,專案中請放到raw資原始檔下, myssl.cer怎麼生成, 請用pc瀏覽器自動匯出證書,儲存, 還不清楚的話,我會醉醉。

想對某個api不想快取:

  novate.addCache(false)

想對某個api不想cookie持久 :

  novate.addCookie(false)

同樣很多人想問 我想對novate進行擴充套件,咋辦?別擔心,Novate也提供了以下方法:

  novate.addInterceptor()
             .addCallAdapterFactory()
             .callFactory()
             .proxy()
             .client()

上面只是列舉了幾個簡單的api,更多的還是沿用的Retrofit的方法名,Retrofit怎麼使用,Novate就怎麼用.

RxJava怎麼處理?

 observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

內部統一已進行執行緒控制,所有請求都採用以上執行緒形式,無需你手動新增。

RxApi

主要處理請求的API,

包含RxGet, RxPost, RxDelete,RxPut, RxBody,RxFrom, RxUpLoad,RxDownLoad.

使用基本APi之前 請閱讀對RxCallBack的介紹。

RxGet

進行get方式的請求呼叫,多種返回結果的方式供你選擇,返回不同的資料型別參考請看RxCallBack的介紹。

基礎使用:

返回String

  new Novate.Builder(this)
           .baseUrl("http://ip.taobao.com/")
           .build()
           .rxGet("service/getIpInfo.php", parameters, new RxStringCallback() {

            @Override
            public void onStart(Object tag) {
                super.onStart(tag);
            }

            @Override
            public void onNext(Object tag, String response) {
            }

            @Override
            public void onError(Object tag, Throwable e) {
            }

            @Override
            public void onCancel(Object tag, Throwable e) {
            }
        });

返回Bean

 novate.rxGet("path or url", parameters, new RxResultCallback<ResultModel>() {



    });

返回List

    new Novate.Builder(this)
            .baseUrl("http://xxx.com/")
            .build()
            .rxGet("service/getList", parameters, new RxListCallback<List<MusicBookCategory>>() {
                @Override
                public void onNext(Object tag, int code, String message, List<MusicBookCategory> response) {

                }


                @Override
                public void onError(Object tag, Throwable e) {

                }

                @Override
                public void onCancel(Object tag, Throwable e) {

                }
            });

返回File

 novate.rxGet("path or url", null, new RxFileCallBack(filePath, "name.jpg") {



    });

RxPost:

進行Post方式的請求呼叫

返回String

   novate.rxPost("path or url", parameters, new RxStringCallback() {


    });

返回Bean

 novate.rxPost("path or url", parameters, new RxResultCallback<ResultModel>() {



    });

返回List

 novate.rxPost("path or url", parameters, new RxListCallback<List<ResultModel>>() {


       ....

    });

返回File

 novate.rxPost("path or url", null, new RxFileCallBack(filePath, "name.jpg") {



    });

RxUpLoad

以Body方式post資料,可以上報載檔案,圖片,多媒體檔案等。

Novate提供了2種方式上傳檔案。body和part模式,Body不包含key值,part包含key值。

RxUploadWithBody

以Body方式post資料,可以上報檔案,圖片等。

    String mPath = uploadPath; //"you File path ";
    String url = "http:/xxx.com";

    novate.rxUploadWithBody(url, new File(mPath), new RxStringCallback() {

        @Override
        public void onNext(Object tag, String response) {
        }

        @Override
        public void onError(Object tag, Throwable e) {

        }

        @Override
        public void onCancel(Object tag, Throwable e) {


        }
    });

}

RxUploadWithPart

上傳檔案,預設的key是 *image *

    String mPath = uploadPath; //"you File path ";
     String url = "http:/xxx.com";
    File file = new File(mPath);
    novate.rxUploadWithPart(url, file, new RxStringCallback() {

        @Override
        public void onError(Object tag, Throwable e) {
        }

        @Override
        public void onCancel(Object tag, Throwable e) {

        }

        @Override
        public void onNext(Object tag, String response) {
        }


    });

如果自定義key 請看下面

    String mPath = uploadPath; //"you File path ";
    String url = "http:/xxx.com";

    File file = new File(mPath);
    RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data; charset=utf-8"), file);

    final NovateRequestBody requestBody = Utils.createNovateRequestBody(requestFile, new UpLoadCallback() {

        @Override
        public void onProgress(Object tag, int progress, long speed, boolean done) {

            updateProgressDialog(progress);
        }
    });


    MultipartBody.Part body2 =
            MultipartBody.Part.createFormData("image", file.getName(), requestBody);
    //請將image改成你和伺服器約定好的key

    novate.rxUploadWithPart(url, body2, new RxStringCallback() {
        @Override
        public void onError(Object tag, Throwable e) {
        }

        @Override
        public void onCancel(Object tag, Throwable e) {

        }

        @Override
        public void onNext(Object tag, String response) {
        }


    });

上傳多檔案:

rxUploadWithPartListByFile:

        List<File> fileList = new ArrayList<>();
         fileList.add(file);
         fileList.add(file);
         fileList.add(file);
        novate.rxUploadWithPartListByFile(url, fileList, new RxStringCallback() {

            @Override
            public void onStart(Object tag) {
                super.onStart(tag);
            }

            @Override
            public void onNext(Object tag, String response) {
            }

            @Override
            public void onError(Object tag, Throwable e) {
            }

        });

RxDownLoad

以get方式下載資料,可以下載檔案,圖片,多媒體檔案。

使用rxGet()實現下載:

   String downUrl = "http://wap.dl.pinyin.sogou.com/wapdl/hole/201512/03/SogouInput_android_v7.11_sweb.apk";

    novate.rxGet(downUrl, parameters, new RxFileCallBack(FileUtil.getBasePath(this), "test.apk") {

        @Override
        public void onStart(Object tag) {
            super.onStart(tag);
            showPressDialog();
        }

        @Override
        public void onNext(Object tag, File file) {
            dismissProgressDialog();
        }

        @Override
        public void onProgress(Object tag, float progress, long downloaded, long total) {
            updateProgressDialog((int) progress);
        }

        @Override
        public void onError(Object tag, Throwable e) {

        }

        @Override
        public void onCancel(Object tag, Throwable e) {

        }

        @Override
        public void onCompleted(Object tag) {
            super.onCompleted(tag);

        }
    });

RxDown()下載

String downUrl = "http://wap.dl.pinyin.sogou.com/wapdl/hole/201512/03/SogouInput_android_v7.11_sweb.apk";
new Novate.Builder(this)
          .baseUrl(baseUrl)
          .build()
          .rxDownload(downUrl, new RxFileCallBack() {
                    @Override
                    public void onStart(Object tag) {
                        super.onStart(tag);
                        showPressDialog();
                    }

                    @Override
                    public void onNext(Object tag, File file) {
                        dismissProgressDialog();
                        Toast.makeText(ExampleActivity.this, "下載成功!", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onProgress(Object tag, float progress, long downloaded, long total) {
                        updateProgressDialog((int) progress);
                    }

                    @Override
                    public void onProgress(Object tag, int progress, long speed, long transfered, long total) {
                        super.onProgress(tag, progress, speed, transfered, total);
                        updateProgressDialog((int) progress);
                    }

                    @Override
                    public void onError(Object tag, Throwable e) {

                    }

                    @Override
                    public void onCancel(Object tag, Throwable e) {

                    }

                    @Override
                    public void onCompleted(Object tag) {
                        super.onCompleted(tag);
                        dismissProgressDialog();
                    }
                });

Custom Api

以上方法預設會處理Novate自帶的BaseApiService,如果預設的BaseApiService無法滿足你的需求時,Novate同樣支援你自己的ApiService。

定義一個你自己的API:

MyAPI

 public interface MyAPI {

   @GET("url")
  Observable<MyBean> getdata(@QueryMap Map<String, String> maps);

 }

Execute Call

通過novate提供create()例項化你的API

 MyAPI myAPI = novate.create(MyAPI.class);

通過novate.call()來執行你的介面,你也不用關心,novate內部同樣已進行RxJava執行緒控制。

 novate.call(myAPI.getdata(parameters),
            new BaseSubscriber<MyBean>(ExempleActivity.this) {

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(MyBean MyBean) {
                }
            });

}

取消

每執行novate.xxx() 給上層返回了一個Subscription,上層可以呼叫unsubscribe()來進行取消!

     if (!subscription.isUnsubscribed()) {
         subscription.unsubscribe();
     }

取消

每執行novate.xxx() 給上層返回了一個Subscription,上層可以呼叫unsubscribe()來進行取消!

注意

本框架自帶視後端資料為:
{int code, String message(msg), T data(result)}

如果你的API返回的資料格式不是上面的預設格式,若想用原生的資料,請用RxStringCallback, 或者RxGenericsCallback, 這很好的解決了資料格式不相容問題。

感謝

感謝一直以來提供思路,和測試的朋友,不斷提供建議和思路,讓我不斷完善novate,。 有的人看過或者讀過後覺得此框架定製化嚴重,也有的人覺得挺好,所以提供了可配置方案:

如果想改變 返回資料 走成功回撥的流程,實際上也提供了動態化的方案, 上層的callback可以實現需要的rxcallback進行以下方式:

/**
 * 子類可以複寫 預設不做對後端的資料校驗 子類指定自己的校驗規則
 */
public boolean isReponseOk(Object tag, ResponseBody responseBody) {
     //對原始資料處理 是否視為為成功
     ......
    return 你的判斷;
}

如果你覺得此框架的業務碼和錯誤碼定的太死,其實框架已提供定製化方案,比如可以在你的專案中Assets中修改config檔案:

如果想用預設的成功狀態碼: 0,不成功為非0的情況,可忽略以下的配置檔案。


{
"isFormat": "false",
"sucessCode": [
"1",
"0",
"1001"
],
"error": {
"1001": "網路異常"
}
}

如果不想對結果格式化檢查,請將isFormat設定為:false.

如果需要修改sucessCode的成功業務,請將你的成功的業務碼加入到sucessCode節點中,參考上面的做法。

錯誤碼

需要對錯誤碼進行自定義翻譯,請配置相關error資訊,具體可配置成:

             `{
           "isFormat": "false",
              "sucessCode": [
                "1",
             "0",
              "1001"
            ],
            "error": {
              "1001": "網路異常",
              "1002": "加入你的異常資訊"
                     }
             }

待開發

目前1.X並沒有完全運用RxJava2.0的新特性,筆者以開始聯合@一葉飄舟 做相容RxJava2.x的APi的工作, 目前Novate很遺憾無法為你提供壓棧,背壓式服務!
在連續非同步多個api時,諸如指定序列請求網路的場景,大白話就是你要根據上一個api的返回值再執行下一個api的情況,Novate1.x只能是靠開發者在上層的成功回撥中執行,如果是1.x是對retrofit的強化,那麼novate2.x將是對RxJava2的運用強化。

結束

如果你對本框架有無法滿足你的需求或有何更好的想法,請及時聯絡我進行交流!歡迎您的star.

如果第一時間交流請加QQ 1057531664 或者關注本人的微信公眾號!

開發者技術前線

原始碼