RxJava+Retrofit+OkHttp深入淺出-終極封裝六特殊篇(變種String替換Gson自由擴充套件)
背景
在之前的封裝1-5Rxjava+ReTrofit+okHttp深入淺出-終極封裝中我們都是通過傳統的GsonConverterFactory自動解析,這樣做確實很方便,使用者能直接獲取返回的物件,不用關心具體的轉換,但是:這隨之而來有很多的缺陷(雖然官網推薦這樣使用);
比如:無法使用其他第三發轉換框架;泛型無法中間傳遞,封裝無法統一處理快取結果;回撥資訊無法統一處理;伺服器返回格式不嚴謹null解析異常……….
所以我們在享受它遍歷的同時也被迫的要限制做很多的處理,限制我們的擴充套件!
本章就介紹如何放棄GsonConverterFactory,直接返回String,擴充套件我們的封裝!(封裝的整體思想和之前的封裝一樣,所以不會有大的改動!)
無須擔心,本篇封裝單獨作為一個專案和之前封裝分開,便於大家選擇!
效果
功能
完全具備和之前封裝一樣的功能,這裡改用fastjson處理
1.Retrofit+Rxjava+okhttp基本使用方法
2.統一處理請求資料格式
3.統一的ProgressDialog和回撥Subscriber處理
4.取消http請求
5.預處理http請求
6.返回資料的統一判斷
7.失敗後的retry處理
8.RxLifecycle管理生命週期,防止洩露
9.檔案上傳下載(支援多檔案,斷點續傳)
10.Cache資料持久化和資料庫(greenDao)兩種快取機制
11.一對多回撥介面處理
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
對比
話說沒有比較就沒有進步,所以大家比較下前後封裝的各自的優缺點,自行選擇合適自己的方案!
使用
Gson方案:
// 完美封裝簡化版
private void simpleDo() {
SubjectPostApi postEntity = new SubjectPostApi(simpleOnNextListener,this);
postEntity.setAll(true);
HttpManager manager = HttpManager.getInstance();
manager.doHttpDeal(postEntity);
}
// 回撥一一對應
HttpOnNextListener simpleOnNextListener = new HttpOnNextListener<List<SubjectResulte>>() {
@Override
public void onNext(List<SubjectResulte> subjects) {
tvMsg.setText("網路返回:\n" + subjects.toString());
}
@Override
public void onCacheNext(String cache) {
/*快取回撥*/
Gson gson=new Gson();
java.lang.reflect.Type type = new TypeToken<BaseResultEntity<List<SubjectResulte>>>() {}.getType();
BaseResultEntity resultEntity= gson.fromJson(cache, type);
tvMsg.setText("快取返回:\n"+resultEntity.getData().toString() );
}
/*使用者主動呼叫,預設是不需要覆寫該方法*/
@Override
public void onError(Throwable e) {
super.onError(e);
tvMsg.setText("失敗:\n" + e.toString());
}
/*使用者主動呼叫,預設是不需要覆寫該方法*/
@Override
public void onCancel() {
super.onCancel();
tvMsg.setText("取消請求");
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
String方案
// 完美封裝簡化版
private void simpleDo() {
/*初始化資料*/
manager=new HttpManager(this,this);
postEntity = new SubjectPostApi();
postEntity.setAll(true);
manager.doHttpDeal(postEntity);
}
@Override
public void onNext(String resulte, String mothead) {
/*post返回處理*/
if(mothead.equals(postEntity.getMothed())){
List<SubjectResulte> subjectResulte= JSONObject.parseArray(resulte,SubjectResulte.class);
tvMsg.setText("post返回:\n"+subjectResulte.toString() );
}
/*上傳返回處理*/
if(mothead.equals(uplaodApi.getMothed())){
UploadResulte uploadResulte=JSONObject.parseObject(resulte,UploadResulte.class);
tvMsg.setText("上傳成功返回:\n"+uploadResulte.getHeadImgUrl());
Glide.with(MainActivity.this).load(uploadResulte.getHeadImgUrl()).skipMemoryCache(true).into(img);
}
}
@Override
public void onError(Throwable e) {
tvMsg.setText("失敗:\n" + e.toString());
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
Gson封裝方案中,我們採用了一一對應的返回原則,將所以的請求資料引數都放入到baseApi中,返回放入對應的HttpOnNextListener 中
String方案中我們則採用一對多原則,將回撥和請求分開處理,公用一個回撥,通過回撥中的mothead來區分不同的介面,所以上述可以看見後者裡面其實還處理了上傳的回撥處理!
從封裝的用法上可以看出:
優點:String封裝更加的靈活,可以指定Gson轉換的第三方工具,統一的結果返回處理程式碼更加的少(可以完美解決快取無法統一回撥的問題);
同樣也有缺點:String封裝無法自動解析結果型別,需要手動處理(我反而覺得這也是它的優點,更加的靈活,個人看法)
實現
由於是基於之前的封裝修改,所以前提是瞭解之前的封裝以後才能完全瞭解一下的修改實現思路Rxjava+ReTrofit+okHttp深入淺出-終極封裝
1.替換GsonConverterFactory
由於GsonConverterFactory會自動解析Gson,替換成直接返回String的ScalarsConverterFactory
匯入相關包(為了區別-使用fastjson可自由擴充套件)
compile 'com.squareup.retrofit2:converter-scalars:+'
compile 'com.alibaba:fastjson:+'
- 1
- 2
- 1
- 2
替換
compile 'com.squareup.retrofit2:converter-gson:+'
compile 'com.google.code.gson:gson:+'
- 1
- 2
- 1
- 2
2.修改retrofit構建
ScalarsConverterFactory替換GsonConverterFactory
/*建立retrofit物件*/
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(basePar.getBaseUrl())
.build();
HttpService httpService = retrofit.create(HttpService.class);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
替換
/*建立retrofit物件*/
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(basePar.getBaseUrl())
.build();
HttpService httpService = retrofit.create(HttpService.class);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.修改快取記錄位置
由於之前是為了防止gson重複解析,將快取放入到自定義CookieInterceptor中;既然現在不需要自動轉換,直接返回String,所以直接將快取資料處理放入到ProgressSubscriber的onNext中處理;
修改1:去掉CookieInterceptor
//手動建立一個OkHttpClient並設定超時時間快取等設定
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new CacheInterceptor());
builder.addNetworkInterceptor(new CacheInterceptor());
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
替換
//手動建立一個OkHttpClient並設定超時時間快取等設定
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addNetworkInterceptor(new CacheInterceptor());
builder.addInterceptor(new CookieInterceptor(basePar.isCache()));
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
修改二:實現快取處理
在onNext中實現快取處理
/**
* 將onNext方法中的返回結果交給Activity或Fragment自己處理
*
* @param t 建立Subscriber時的泛型型別
*/
@Override
public void onNext(T t) {
/*快取處理*/
if(api.isCache()){
CookieResulte resulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
long time=System.currentTimeMillis();
/*儲存和更新本地資料*/
if(resulte==null){
resulte =new CookieResulte(api.getUrl(),t.toString(),time);
CookieDbUtil.getInstance().saveCookie(resulte);
}else{
resulte.setResulte(t.toString());
resulte.setTime(time);
CookieDbUtil.getInstance().updateCookie(resulte);
}
}
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onNext((String) t,api.getMothed());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
4.修改回撥介面資訊
由於現在通過String直接返回,所以可以將成功回撥和快取回撥合並處理;另一方面沒有了泛型的限制,在回撥時可以通過介面請求引數實現一對多回撥處理;
/**
* 成功回撥處理
* Created by WZG on 2016/7/16.
*/
public interface HttpOnNextListener {
/**
* 成功後回撥方法
* @param resulte
* @param method
*/
void onNext(String resulte,String method);
/**
* 失敗或者錯誤方法
* 主動呼叫,更加靈活
* @param e
*/
void onError(Throwable e);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
5.修改BaseApi
由於取消了泛型返回的機制,所以在Func1判斷時需要手動轉換資料;這裡示例fastjeson用法轉換
@Override
public String call(T httpResult) {
BaseResultEntity baseResulte= JSONObject.parseObject(httpResult.toString(),BaseResultEntity.class);
if (baseResulte.getRet() == 0) {
throw new HttpTimeException(baseResulte.getMsg());
}
return baseResulte.getData();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
替換
@Override
public T call(BaseResultEntity<T> httpResult) {
if (httpResult.getRet() == 0) {
throw new HttpTimeException(httpResult.getMsg());
}
return httpResult.getData();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
6.修改結果基礎類BaseResultEntity
將泛型資料改成String資料型別
/**
* 回撥資訊統一封裝類
* Created by WZG on 2016/7/16.
*/
public class BaseResultEntity {
// 判斷標示
private int ret;
// 提示資訊
private String msg;
//顯示資料(使用者需要關心的資料)
private String data;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
替換
/**
* 回撥資訊統一封裝類
* Created by WZG on 2016/7/16.
*/
public class BaseResultEntity<T> {
// 判斷標示
private int ret;
// 提示資訊
private String msg;
//顯示資料(使用者需要關心的資料)
private T data;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
7.合併快取和成功回到返回處理
由於取消泛型,快取和成統一處理所以需要修改
/**
* 訂閱開始時呼叫
* 顯示ProgressDialog
*/
@Override
public void onStart() {
showProgressDialog();
/*快取並且有網*/
if(api.isCache()&& AppUtil.isNetworkAvailable(MyApplication.app)){
/*獲取快取資料*/
CookieResulte cookieResulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
if(cookieResulte!=null){
long time= (System.currentTimeMillis()-cookieResulte.getTime())/1000;
if(time< api.getCookieNetWorkTime()){
if( mSubscriberOnNextListener.get()!=null){
mSubscriberOnNextListener.get().onNext(cookieResulte.getResulte(),api.getMothed());
}
onCompleted();
unsubscribe();
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
替換
/**
* 訂閱開始時呼叫
* 顯示ProgressDialog
*/
@Override
public void onStart() {
showProgressDialog();
/*快取並且有網*/
if(api.isCache()&& AppUtil.isNetworkAvailable(MyApplication.app)){
/*獲取快取資料*/
CookieResulte cookieResulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
if(cookieResulte!=null){
long time= (System.currentTimeMillis()-cookieResulte.getTime())/1000;
if(time< api.getCookieNetWorkTime()){
if( mSubscriberOnNextListener.get()!=null){
mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
}
onCompleted();
unsubscribe();
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
8.修改一對多回撥處理
沒有了泛型,可以修改HttpManager,採用動態建立,動態回撥的方法解決多巢狀耦合的問題
修改1:去掉預設構造傳參
public BaseApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
setListener(listener);
setRxAppCompatActivity(rxAppCompatActivity);
setShowProgress(true);
setCache(true);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
修改2:新增HttpManager動態傳參
/**
* http互動處理類
* Created by WZG on 2016/7/16.
*/
public class HttpManager {
/*弱引用物件*/
private SoftReference<HttpOnNextListener> onNextListener;
private SoftReference<RxAppCompatActivity> appCompatActivity;
public HttpManager(HttpOnNextListener onNextListener, RxAppCompatActivity appCompatActivity) {
this.onNextListener=new SoftReference(onNextListener);
this.appCompatActivity=new SoftReference(appCompatActivity);
}
*******************
*******************
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
修改3:通過method動態判斷介面返回
public class MainActivity extends RxAppCompatActivity implements HttpOnNextListener{
@Override
public void onNext(String resulte, String method) {
/*post返回處理*/
if(method.equals(postEntity.getMothed())){
*******
}
/*上傳返回處理*/
if(method.equals(uplaodApi.getMothed())){
*********
}
}
@Override
public void onError(Throwable e) {
tvMsg.setText("失敗:\n" + e.toString());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
大功告成!
下載模組
由於下載模組是獨立存在,所以基本沒有修改,唯一修改的地方就是將HttpDownManager中的GsonConverterFactory替換成ScalarsConverterFactory即可!
總結
通過自定義String型別的返回處理方式,有效的解決了之前Gson自動轉換的問題
-
1.一對一返回問題(程式碼量多)
-
2.快取回撥無法和成功統一處理
-
3.無法指定gson轉換第三方庫
-
4.回撥監聽的多巢狀(耦合度大)
-
5.解決伺服器資料null異常
注意:這裡只是給大家提供了一個不同的解決方案,Gson自動解析返回的方案也是有它的優點,可以大大的減少開發的工作量,優缺點也很明顯;孰好孰壞自行判斷,自行選擇適合自己的方案(個人偏向後者String返回,比較靈活)
終極封裝專欄
原始碼
建議
相關文章
- RxRetrofit - 終極封裝 - 深入淺出 & 擴充套件 String封裝套件
- RxJava+Retrofit+OkHttp 深入淺出-終極封裝一RxJavaHTTP封裝
- RxJava+Retrofit+OkHttp深入淺出-終極封裝三(檔案上傳)RxJavaHTTP封裝
- RxJava+Retrofit+OkHttp深入淺出-終極封裝五(資料持久化)RxJavaHTTP封裝持久化
- RxJava+Retrofit+OkHttp深入淺出-終極封裝七(異常處理)RxJavaHTTP封裝
- RxRetrofit - 終極封裝 - 深入淺出 & 異常封裝
- RxRetrofit-終極封裝-深入淺出&入門封裝
- RxRetrofit – 終極封裝 – 深入淺出 & 資料快取封裝快取
- RxRetrofit - 終極封裝 - 深入淺出 & 斷點續傳封裝斷點
- RxRetrofit - 終極封裝 - 深入淺出 & 檔案上傳封裝
- RxRetrofit - 終極封裝 - 深入淺出 & 資料快取封裝快取
- RxRetrofit-終極封裝-深入淺出&網路請求封裝
- RxJava+Retrofit+OkHttp深入淺出-mvp(使用篇)RxJavaHTTPMVP
- Shell 中的命令替換及引數擴充套件套件
- 擴充套件篇套件
- Tomcat深入淺出——最終章(六)Tomcat
- Swift 核心動畫 面向協議 擴充套件封裝Swift動畫協議套件封裝
- JavaScript String 物件擴充套件方法JavaScript物件套件
- WPF如何封裝一個可擴充套件的Window封裝套件
- 自由擴充套件你的專案——Builder模式套件UI模式
- Java替換各種特殊字元工具類Java字元
- 我的第一個擴充套件包釋出啦-封裝明道雲API套件封裝API
- Dapper的封裝、二次封裝、官方擴充套件包封裝,以及ADO.NET原生封裝APP封裝套件
- Solon詳解(六)- Solon的校驗擴充套件框架使用與擴充套件套件框架
- JavaScript擴充套件原型鏈淺析JavaScript套件原型
- PS終極數字混合擴充套件皮膚:Raya Pro 5漢化版套件
- ES6 -- String 擴充套件方法解析套件
- php7安裝redis擴充套件和memcache擴充套件PHPRedis套件
- YAML 擴充套件安裝YAML套件
- Yac 擴充套件安裝套件
- PHP 擴充套件安裝PHP套件
- mongodb擴充套件安裝MongoDB套件
- sphinxphp擴充套件安裝PHP套件
- 淺談Kotlin語法篇之擴充套件函式(五)Kotlin套件函式
- perl替換特殊字元字元
- mysql替換特殊字元MySql字元
- java 替換特殊字元Java字元
- Gson泛型封裝泛型封裝