亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入淺出RxJava+Retrofit+OkHttp網絡請求

 更新時間:2017年11月17日 09:55:59   作者:wzgiceman  
本篇文章主要介紹了深入淺出RxJava+Retrofit+OkHttp網絡請求,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

淺談RxJava+Retrofit+OkHttp 封裝使用 之前發(fā)出后收到很多朋友的關注,原本只是自己學習后的一些經驗總結,但是有同學運用到實戰(zhàn)當中,這讓我很惶恐,所有后續(xù)一直更新了很多次版本,有些地方難免有所變動導致之前的博客有所出入,正好最近受到掘金邀請內測博客,所以決定重新寫一版,按照最后迭代完成的封裝詳細的講述一遍,歡迎大家關注!

注意:由于本章的特殊性,后續(xù)文章比較長而且復雜,涉及內容也很多,所以大家準備好茶水,前方高能預警。

簡介:

Retrofit: Retrofit是Square 公司開發(fā)的一款正對Android 網絡請求的框架。底層基于OkHttp 實現(xiàn),OkHttp 已經得到了google 官方的認可。

OkHttp: 也是Square 開源的網絡請求庫

RxJava:RxJava 在 GitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM 上使用可觀測的序列來組成異步的、基于事件的程序的庫)。這就是 RxJava ,概括得非常精準??傊褪亲尞惒讲僮髯兊梅浅:唵?。

各自的職責:Retrofit 負責請求的數(shù)據和請求的結果,使用接口的方式呈現(xiàn),OkHttp 負責請求的過程,RxJava 負責異步,各種線程之間的切換。

RxJava + Retrofit + okHttp 已成為當前Android 網絡請求最流行的方式。

封裝成果

封裝完以后,具有如下功能:

    1.Retrofit+Rxjava+okhttp基本使用方法
    2.統(tǒng)一處理請求數(shù)據格式
    3.統(tǒng)一的ProgressDialog和回調Subscriber處理
    4.取消http請求
    5.預處理http請求
    6.返回數(shù)據的統(tǒng)一判斷
    7.失敗后的retry封裝處理
    8.RxLifecycle管理生命周期,防止泄露

實現(xiàn)效果:

具體使用

封裝后http請求代碼如下

//  完美封裝簡化版
  private void simpleDo() {
    SubjectPost postEntity = new SubjectPost(simpleOnNextListener,this);
    postEntity.setAll(true);
    HttpManager manager = HttpManager.getInstance();
    manager.doHttpDeal(postEntity);
  }

  //  回調一一對應
  HttpOnNextListener simpleOnNextListener = new HttpOnNextListener<List<Subject>>() {
    @Override
    public void onNext(List<Subject> subjects) {
      tvMsg.setText("已封裝:\n" + subjects.toString());
    }

    /*用戶主動調用,默認是不需要覆寫該方法*/
    @Override
    public void onError(Throwable e) {
      super.onError(e);
      tvMsg.setText("失敗:\n" + e.toString());
    }
  };

是不是很簡單?你可能說這還簡單,好咱們對比一下正常使用Retrofit的方法

/** 
  * Retrofit加入rxjava實現(xiàn)http請求 
  */ 
  private void onButton9Click() { 
    //手動創(chuàng)建一個OkHttpClient并設置超時時間 
    okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
    builder.connectTimeout(5, TimeUnit.SECONDS); 

    Retrofit retrofit = new Retrofit.Builder() 
        .client(builder.build()) 
        .addConverterFactory(GsonConverterFactory.create()) 
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
        .baseUrl(HttpManager.BASE_URL) 
        .build(); 

/    加載框 
    final ProgressDialog pd = new ProgressDialog(this); 

    HttpService apiService = retrofit.create(HttpService.class); 
    Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true); 
    observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) 
        .subscribe( 
            new Subscriber<RetrofitEntity>() { 
              @Override 
              public void onCompleted() { 
                if (pd != null && pd.isShowing()) { 
                  pd.dismiss(); 
                } 
              } 

              @Override 
              public void onError(Throwable e) { 
                if (pd != null && pd.isShowing()) { 
                  pd.dismiss(); 
                } 
              } 

              @Override 
              public void onNext(RetrofitEntity retrofitEntity) { 
                tvMsg.setText("無封裝:\n" + retrofitEntity.getData().toString()); 
              } 

              @Override 
              public void onStart() { 
                super.onStart(); 
                pd.show(); 
              } 
            } 

        ); 
  }

可能你發(fā)現(xiàn)確是代碼有點多,但是更加可怕的是,如果你一個activity或者fragment中多次需要http請求,你需要多次重復的寫回調處理(一個回到就有4個方法呀?。。?!反正我是忍受不了),而且以上處理還沒有做過多的判斷和錯誤校驗就如此復雜!~好了介紹完了,開始咱們的優(yōu)化之路吧!

項目結構:

Retrofit

咱家今天的主角來了,咱們也深入淺出一下了解下Retrofit使用,前方高能,如果你是深度Retrofit選手請直接跳過本節(jié)?。?!

1.首先確保在AndroidManifest.xml中請求了網絡權限

<uses-permission android:name="android.permission.INTERNET"/>

2.在app/build.gradle添加引用

 /*rx-android-java*/
  compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
  compile 'com.trello:rxlifecycle:1.0'
  compile 'com.trello:rxlifecycle-components:1.0'
  /*rotrofit*/
  compile 'com.squareup.retrofit2:retrofit:2.1.0'
  compile 'com.squareup.retrofit2:converter-gson:2.0.0'
  compile 'com.google.code.gson:gson:2.8.0'

3.常用注解

這里介紹一些常用的注解的使用

  1. @Query、@QueryMap:用于Http Get請求傳遞參數(shù)
  2. @Field:用于Post方式傳遞參數(shù),需要在請求接口方法上添加@FormUrlEncoded,即以表單的方式傳遞參數(shù)
  3. @Body:用于Post,根據轉換方式將實例對象轉化為對應字符串傳遞參數(shù).比如Retrofit添加GsonConverterFactory則是將body轉化為gson字符串進行傳遞
  4. @Path:用于URL上占位符
  5. @Part:配合@Multipart使用,一般用于文件上傳
  6. @Header:添加http header
  7. @Headers:跟@Header作用一樣,只是使用方式不一樣,@Header是作為請求方法的參數(shù)傳入,@Headers是以固定方式直接添加到請求方法上

ReTrofit基本使用:

首先給定一個測試接口文檔,后面的博客中我們都是用這個接口調試

/** 
 * @api  videoLink  50音圖視頻鏈接 
 * @url  http://www.izaodao.com/Api/AppFiftyToneGraph/videoLink 
 * @method post 
 * @param once_no bool(選填,ture無鏈接) 一次性獲取下載地址 
 * @return json array( 
 * ret:1成功,2失敗 
 * msg:信息 
 * data:{ 
 *    name:視頻名稱 
 *    title:標題 
 * } 
 )

1.初始化retrofit

要向一個api發(fā)送我們的網絡請求 ,我們需要使用Retrofit builder類并指定service的base URL(通常情況下就是域名)。

String BASE_URL = " http://www.izaodao.com/Api/" 
  Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl(BASE_URL) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .build();

2.設置接口service

注意到每個endpoint 都指定了一個關于HTTP(GET, POST, 等等。) 方法的注解以及用于分發(fā)網絡調用的方法。而且這些方法的參數(shù)也可以有特殊的注解。

/** 
 * 接口地址 
 * Created by WZG on 2016/7/16. 
 */ 
public interface MyApiEndpointInterface { 
  @POST("AppFiftyToneGraph/videoLink") 
  Call<RetrofitEntity> getAllVedio(@Body boolean once_no)       
}

3.得到call然后同步處理處理回調:

MyApiEndpointInterface apiService = retrofit.create(MyApiEndpointInterface.class); 
Call<RetrofitEntity> call = apiService.getAllVedio(true); 
call.enqueue(new Callback<RetrofitEntity>() { 
  @Override 
  public void onResponse(Response<RetrofitEntity> response, Retrofit retrofit) { 
    RetrofitEntity entity = response.body(); 
    Log.i("tag", "onResponse----->" + entity.getMsg()); 
  } 

  @Override 
  public void onFailure(Throwable t) { 
    Log.i("tag", "onFailure----->" + t.toString()); 

  } 
});

這就是簡單的Retrofit使用步驟,接下來我們結合RxJava講述

ReTrofit+Rxjava基本使用

對比之前的Retrofit使用

1.在于我們需要修改service接口返回信息我們需要返回一個Observable對象

@POST("AppFiftyToneGraph/videoLink") 
Observable<RetrofitEntity> getAllVedioBy(@Body boolean once_no);

2.然后初始化Retrofit需要添加對Rxjava的適配,注意一定要retrofit2才有這個功能哦

Retrofit retrofit = new Retrofit.Builder() 
        .client(builder.build()) 
        .addConverterFactory(GsonConverterFactory.create()) 
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
        .baseUrl(HttpManager.BASE_URL) 
        .build();

3.回調通過RxJava處理

HttpService apiService = retrofit.create(HttpService.class); 
    Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true); 
    observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) 
        .subscribe( 
            new Subscriber<RetrofitEntity>() { 
              @Override 
              public void onCompleted() { 
              } 

              @Override 
              public void onError(Throwable e) {                
              } 

              @Override 
              public void onNext(RetrofitEntity retrofitEntity) { 
                tvMsg.setText("無封裝:\n" + retrofitEntity.getData().toString()); 
              }              
            } 

        );

簡單的RxJava集合Retrofit的使用就介紹完了,同樣的可以發(fā)現(xiàn)使用起來很多重復性的代碼,而且使用也不是那么簡單,所以才有了下面的封裝

ReTrofit+Rxjava進階封裝之路

先來一張流程圖壓壓驚

請求數(shù)據封裝

1.參數(shù)

首先需要封裝的使我們的數(shù)據類,在數(shù)據類中需要封裝請求中用到的相關數(shù)據的設置,比如請求參數(shù)、方法、加載框顯示設置等等

public abstract class BaseApi<T> implements Func1<BaseResultEntity<T>, T> {
  //rx生命周期管理
  private SoftReference<RxAppCompatActivity> rxAppCompatActivity;
  /*回調*/
  private SoftReference<HttpOnNextListener> listener;
  /*是否能取消加載框*/
  private boolean cancel;
  /*是否顯示加載框*/
  private boolean showProgress;
  /*是否需要緩存處理*/
  private boolean cache;
  /*基礎url*/
  private String baseUrl="http://www.izaodao.com/Api/";
  /*方法-如果需要緩存必須設置這個參數(shù);不需要不用設置*/
  private String mothed;
  /*超時時間-默認6秒*/
  private int connectionTime = 6;
  /*有網情況下的本地緩存時間默認60秒*/
  private int cookieNetWorkTime=60;
  /*無網絡的情況下本地緩存時間默認30天*/
  private int cookieNoNetWorkTime=24*60*60*30;
}

注釋很詳細,這里不具體描述了,由于這里是最后封裝完成以后的代碼,所以有些內容本章還會部分不會涉及,因為功能太多,還是按照一開始的博客章節(jié)講解。

2.抽象api接口

  /**
   * 設置參數(shù)
   *
   * @param retrofit
   * @return
   */
  public abstract Observable getObservable(Retrofit retrofit);

通過子類也即是我們的具體api接口,通過getObservable實現(xiàn)service中定義的接口方法,例如:

public class SubjectPostApi extends BaseApi {
   xxxxxxx
   xxxxxxx

 @Override
  public Observable getObservable(Retrofit retrofit) {
    HttpPostService service = retrofit.create(HttpPostService.class);
    return service.getAllVedioBys(isAll());
  }
}

通過傳入的Retrofit對象,可以隨意切換挑選Service對象,得到定義的注解方法,初始完成以后返回Observable對象。

3.結果判斷

這里結合RxJava的map方法在服務器返回數(shù)據中,統(tǒng)一處理數(shù)據處理,所以BaseApi<T> implements

Func1<BaseResultEntity<T>, T>,后邊結合結果處理鏈接起來使用
  @Override
  public T call(BaseResultEntity<T> httpResult) {
    if (httpResult.getRet() == 0) {
      throw new HttpTimeException(httpResult.getMsg());
    }
    return httpResult.getData();
  }

由于測試接口,也是當前我們公司接口都是有統(tǒng)一規(guī)則的,想必大家都有這樣的接口規(guī)則,所以才有這里的統(tǒng)一判斷,規(guī)則如下:

 * ret:1成功,2失敗 
 * msg:信息 
 * data:{ 
 *    name:視頻名稱 
 *    title:標題 
 * }

其實上面的接口文檔中就介紹了,統(tǒng)一先通過ret判斷,失敗顯示msg信息,data是成功后的數(shù)據也就是用戶關心的數(shù)據,所以可封裝一個結果對象BaseResultEntity.

4.結果數(shù)據

/**
 * 回調信息統(tǒng)一封裝類
 * Created by WZG on 2016/7/16.
 */
public class BaseResultEntity<T> {
  // 判斷標示
  private int ret;
  //  提示信息
  private String msg;
  //顯示數(shù)據(用戶需要關心的數(shù)據)
  private T data;


  xxxxx get-set xxxxx
}

這里結合BaseApi的Func1判斷,失敗直接拋出一個異常,交個RxJava的onError處理,成功則將用戶關心的數(shù)據傳給Gson解析返回

5.泛型傳遞

BaseResultEntity<T>中的泛型T也就是我們所關心的回調數(shù)據,同樣也是Gson最后解析返回的數(shù)據,傳遞的過程根節(jié)點是通過定義service方法是給定的,例如:

public interface HttpPostService {
  @POST("AppFiftyToneGraph/videoLink")
  Call<RetrofitEntity> getAllVedio(@Body boolean once_no);
}

其中的RetrofitEntity就是用戶關心的數(shù)據類,通過泛型傳遞給最后的接口。

6.強調

很多兄弟通過QQ群反饋給我說,使用一個接口需要寫一個對應的api類繼承BaseApi是不是很麻煩,我這里強調一下,這樣封裝是為了將一個Api接口作為一個對象去封裝,個人覺得有必要封裝成一個類,在日后工程日益增加接口隨著增加的同時,對象的做法更加有利于查找接口和修改接口有利于迭代。

操作類封裝

1初始對象

首先初始化一個單利方便HttpManager請求;這里用了volatile的對象

  private volatile static HttpManager INSTANCE;

  //構造方法私有
  private HttpManager() {
  }

  //獲取單例
  public static HttpManager getInstance() {
    if (INSTANCE == null) {
      synchronized (HttpManager.class) {
        if (INSTANCE == null) {
          INSTANCE = new HttpManager();
        }
      }
    }
    return INSTANCE;
  }

2接口處理和回調處理:

 /**
   * 處理http請求
   *
   * @param basePar 封裝的請求數(shù)據
   */
  public void doHttpDeal(BaseApi basePar) {
    //手動創(chuàng)建一個OkHttpClient并設置超時時間緩存等設置
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
    builder.addInterceptor(new CookieInterceptor(basePar.isCache()));

    /*創(chuàng)建retrofit對象*/
    Retrofit retrofit = new Retrofit.Builder()
        .client(builder.build())
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .baseUrl(basePar.getBaseUrl())
        .build();


    /*rx處理*/
    ProgressSubscriber subscriber = new ProgressSubscriber(basePar);
    Observable observable = basePar.getObservable(retrofit)
        /*失敗后的retry配置*/
        .retryWhen(new RetryWhenNetworkException())
        /*生命周期管理*/
        .compose(basePar.getRxAppCompatActivity().bindToLifecycle())
        /*http請求線程*/
        .subscribeOn(Schedulers.io())
        .unsubscribeOn(Schedulers.io())
        /*回調線程*/
        .observeOn(AndroidSchedulers.mainThread())
        /*結果判斷*/
        .map(basePar);

    /*數(shù)據回調*/
    observable.subscribe(subscriber);
  }

首先通過api接口類BaseApi的實現(xiàn)類中數(shù)據初始化OkHttpClient和Retrofit對象,其中包含了url,超時等,接著通過BaseApi的抽象方法getObservable得到Observable對象,得到Observable對象以后,我們就能隨意的切換現(xiàn)成來處理,整個請求通過compose設定的rxlifecycle來管理生命周期,所以不會溢出和泄露無需任何擔心,最后再服務器數(shù)據返回時,通過map判斷結果,剔除錯誤信息,成功以后返回到自定義的ProgressSubscriber對象中,所以接下來封裝ProgressSubscriber對象。

ProgressSubscriber封裝

ProgressSubscriber其實是繼承于Subscriber,封裝的方法無非是對Subscriber的回調方法的封裝

  1. onStart():開始
  2. onCompleted():結束
  3. onError(Throwable e):錯誤
  4. onNext(T t):成功

1.請求加載框

http請求都伴隨著加載框的使用,所以這里需要在onStart()使用前初始一個加載框,這里簡單的用ProgressDialog代替

/**
 * 用于在Http請求開始時,自動顯示一個ProgressDialog
 * 在Http請求結束是,關閉ProgressDialog
 * 調用者自己對請求數(shù)據進行處理
 * Created by WZG on 2016/7/16.
 */
public class ProgressSubscriber<T> extends Subscriber<T> {
  /*是否彈框*/
  private boolean showPorgress = true;
  /* 軟引用回調接口*/
  private SoftReference<HttpOnNextListener> mSubscriberOnNextListener;
  /*軟引用反正內存泄露*/
  private SoftReference<RxAppCompatActivity> mActivity;
  /*加載框可自己定義*/
  private ProgressDialog pd;
  /*請求數(shù)據*/
  private BaseApi api;


  /**
   * 構造
   *
   * @param api
   */
  public ProgressSubscriber(BaseApi api) {
    this.api = api;
    this.mSubscriberOnNextListener = api.getListener();
    this.mActivity = new SoftReference<>(api.getRxAppCompatActivity());
    setShowPorgress(api.isShowProgress());
    if (api.isShowProgress()) {
      initProgressDialog(api.isCancel());
    }
  }


  /**
   * 初始化加載框
   */
  private void initProgressDialog(boolean cancel) {
    Context context = mActivity.get();
    if (pd == null && context != null) {
      pd = new ProgressDialog(context);
      pd.setCancelable(cancel);
      if (cancel) {
        pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
          @Override
          public void onCancel(DialogInterface dialogInterface) {
            onCancelProgress();
          }
        });
      }
    }
  }


  /**
   * 顯示加載框
   */
  private void showProgressDialog() {
    if (!isShowPorgress()) return;
    Context context = mActivity.get();
    if (pd == null || context == null) return;
    if (!pd.isShowing()) {
      pd.show();
    }
  }


  /**
   * 隱藏
   */
  private void dismissProgressDialog() {
    if (!isShowPorgress()) return;
    if (pd != null && pd.isShowing()) {
      pd.dismiss();
    }
  }
}

由于progress的特殊性,需要指定content而且不能是Application所以這里傳遞一個RxAppCompatActivity,而同時上面的HttpManager同樣需要,所以這里統(tǒng)一還是按照BaseApi傳遞過來,使用軟引用的方式避免泄露。剩下的無非是初始化,顯示和關閉方法,可以詳細看代碼。

2.onStart()實現(xiàn)

在onStart()中需要調用加載框,然后這里還有網絡緩存的邏輯,后面會單獨講解,現(xiàn)在先忽略它的存在。

 /**
   * 訂閱開始時調用
   * 顯示ProgressDialog
   */
  @Override
  public void onStart() {
    showProgressDialog();
    /*緩存并且有網*/
    if (api.isCache() && AppUtil.isNetworkAvailable(RxRetrofitApp.getApplication())) {
       /*獲取緩存數(shù)據*/
      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();
        }
      }
    }
  }

3.onCompleted()實現(xiàn)

 /**
   * 完成,隱藏ProgressDialog
   */
  @Override
  public void onCompleted() {
    dismissProgressDialog();
  }

4.onError(Throwable e)實現(xiàn)

在onError(Throwable e)是對錯誤信息的處理和緩存讀取的處理,后續(xù)會講解,先忽略。

/**
   * 對錯誤進行統(tǒng)一處理
   * 隱藏ProgressDialog
   *
   * @param e
   */
  @Override
  public void onError(Throwable e) {
    dismissProgressDialog();
    /*需要緩存并且本地有緩存才返回*/
    if (api.isCache()) {
      Observable.just(api.getUrl()).subscribe(new Subscriber<String>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {
          errorDo(e);
        }

        @Override
        public void onNext(String s) {
          /*獲取緩存數(shù)據*/
          CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(s);
          if (cookieResulte == null) {
            throw new HttpTimeException("網絡錯誤");
          }
          long time = (System.currentTimeMillis() - cookieResulte.getTime()) / 1000;
          if (time < api.getCookieNoNetWorkTime()) {
            if (mSubscriberOnNextListener.get() != null) {
              mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
            }
          } else {
            CookieDbUtil.getInstance().deleteCookie(cookieResulte);
            throw new HttpTimeException("網絡錯誤");
          }
        }
      });
    } else {
      errorDo(e);
    }
  }

  /*錯誤統(tǒng)一處理*/
  private void errorDo(Throwable e) {
    Context context = mActivity.get();
    if (context == null) return;
    if (e instanceof SocketTimeoutException) {
      Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態(tài)", Toast.LENGTH_SHORT).show();
    } else if (e instanceof ConnectException) {
      Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態(tài)", Toast.LENGTH_SHORT).show();
    } else {
      Toast.makeText(context, "錯誤" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }
    if (mSubscriberOnNextListener.get() != null) {
      mSubscriberOnNextListener.get().onError(e);
    }
  }

5.onNext(T t)實現(xiàn)

  /**
   * 將onNext方法中的返回結果交給Activity或Fragment自己處理
   *
   * @param t 創(chuàng)建Subscriber時的泛型類型
   */
  @Override
  public void onNext(T t) {
    if (mSubscriberOnNextListener.get() != null) {
      mSubscriberOnNextListener.get().onNext(t);
    }
  }

主要是是將得到的結果,通過自定義的接口返回給view界面,其中的軟引用對象mSubscriberOnNextListener是自定義的接口回調類HttpOnNextListener.

6.HttpOnNextListener封裝

現(xiàn)在只需關心onNext(T t)和onError(Throwable e)接口即可,回調的觸發(fā)點都是在上面的ProgressSubscriber中調用

/**
 * 成功回調處理
 * Created by WZG on 2016/7/16.
 */
public abstract class HttpOnNextListener<T> {
  /**
   * 成功后回調方法
   * @param t
   */
  public abstract void onNext(T t);

  /**
   * 緩存回調結果
   * @param string
   */
  public void onCacheNext(String string){

  }

  /**
   * 失敗或者錯誤方法
   * 主動調用,更加靈活
   * @param e
   */
  public void onError(Throwable e){

  }

  /**
   * 取消回調
   */
  public void onCancel(){

  }
}

失敗后的retry處理

這里你可能會問,Retrofit有自帶的retry處理呀,的確Retrofit有自帶的retry處理,但是有很多的局限,先看下使用

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.retryOnConnectionFailure(true);

使用起來還是很方便,只需要調用一個方法即可,但是它是不可控的,也就是沒有辦法設置retry時間次數(shù),所以不太靈活,既然如此還不如自己封裝一下,因為用RxJava實現(xiàn)這個簡直小菜,無形中好像已經給RxJava打了廣告,中毒太深。

很簡單直接上代碼:

 /**
 * retry條件
 * Created by WZG on 2016/10/17.
 */
public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> {
//  retry次數(shù)
  private int count = 3;
//  延遲
  private long delay = 3000;
//  疊加延遲
  private long increaseDelay = 3000;

  public RetryWhenNetworkException() {

  }

  public RetryWhenNetworkException(int count, long delay) {
    this.count = count;
    this.delay = delay;
  }

  public RetryWhenNetworkException(int count, long delay, long increaseDelay) {
    this.count = count;
    this.delay = delay;
    this.increaseDelay = increaseDelay;
  }

  @Override
  public Observable<?> call(Observable<? extends Throwable> observable) {
    return observable
        .zipWith(Observable.range(1, count + 1), new Func2<Throwable, Integer, Wrapper>() {
          @Override
          public Wrapper call(Throwable throwable, Integer integer) {
            return new Wrapper(throwable, integer);
          }
        }).flatMap(new Func1<Wrapper, Observable<?>>() {
          @Override
          public Observable<?> call(Wrapper wrapper) {
            if ((wrapper.throwable instanceof ConnectException
                || wrapper.throwable instanceof SocketTimeoutException
                || wrapper.throwable instanceof TimeoutException)
                && wrapper.index < count + 1) { //如果超出重試次數(shù)也拋出錯誤,否則默認是會進入onCompleted
              return Observable.timer(delay + (wrapper.index - 1) * increaseDelay, TimeUnit.MILLISECONDS);

            }
            return Observable.error(wrapper.throwable);
          }
        });
  }

  private class Wrapper {
    private int index;
    private Throwable throwable;

    public Wrapper(Throwable throwable, int index) {
      this.index = index;
      this.throwable = throwable;
    }
  }
}

使用

到這里,我們第一步封裝已經完成了,下面講解下如何使用,已經看明白的各位看官,估計早就看明白了使用方式,無非是創(chuàng)建一個api對象繼承BaseApi初始接口信息,然后調用HttpManager對象的doHttpDeal(BaseApi basePar)方法,最后靜靜的等待回調類HttpOnNextListener<T>類返回的onNext(T t)成功數(shù)據或者onError(Throwable e)數(shù)據。

其實代碼就是這樣:

api接口對象

/**
 * 測試數(shù)據
 * Created by WZG on 2016/7/16.
 */
public class SubjectPostApi extends BaseApi {
//  接口需要傳入的參數(shù) 可自定義不同類型
  private boolean all;
  /*任何你先要傳遞的參數(shù)*/
//  String xxxxx;

  /**
   * 默認初始化需要給定回調和rx周期類
   * 可以額外設置請求設置加載框顯示,回調等(可擴展)
   * @param listener
   * @param rxAppCompatActivity
   */
  public SubjectPostApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
    super(listener,rxAppCompatActivity);
    setShowProgress(true);
    setCancel(true);
    setCache(true);
    setMothed("AppFiftyToneGraph/videoLink");
    setCookieNetWorkTime(60);
    setCookieNoNetWorkTime(24*60*60);
  }

  public boolean isAll() {
    return all;
  }

  public void setAll(boolean all) {
    this.all = all;
  }

  @Override
  public Observable getObservable(Retrofit retrofit) {
    HttpPostService service = retrofit.create(HttpPostService.class);
    return service.getAllVedioBys(isAll());
  }
}

請求回調

 //  完美封裝簡化版
  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("取消請求");
    }
  };

后續(xù)

到這里,封裝功能中很多功能還沒涉及和講解,后續(xù)會陸續(xù)更新!

先給大家看看為師的完全體功能:

    1.Retrofit+Rxjava+okhttp基本使用方法
    2.統(tǒng)一處理請求數(shù)據格式
    3.統(tǒng)一的ProgressDialog和回調Subscriber處理
    4.取消http請求
    5.預處理http請求
    6.返回數(shù)據的統(tǒng)一判斷
    7.失敗后的retry處理
    8.RxLifecycle管理生命周期,防止泄露
    9.文件上傳下載(支持多文件,斷點續(xù)傳)
    10.Cache數(shù)據持久化和數(shù)據庫(greenDao)兩種緩存機制
    11.異常統(tǒng)一處理

來個圖壓壓驚:

源碼:

RxRetrofit-終極封裝-深入淺出&網絡請求-GitHub

其實我還有一個兄弟版本-傳送門

我不會告訴你其實我還有個更加簡單的版本

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Android如何動態(tài)調整應用字體大小詳解

    Android如何動態(tài)調整應用字體大小詳解

    這篇文章主要給大家介紹了關于Android如何動態(tài)調整應用字體大小的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-05-05
  • Android實現(xiàn)收到新短信后自動發(fā)郵件功能

    Android實現(xiàn)收到新短信后自動發(fā)郵件功能

    這篇文章主要為大家詳細介紹了Android實現(xiàn)收到新短信后自動發(fā)郵件功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Android系統(tǒng)的五種數(shù)據存儲形式實例(二)

    Android系統(tǒng)的五種數(shù)據存儲形式實例(二)

    Android系統(tǒng)有五種數(shù)據存儲形式,分別是文件存儲、SP存儲、數(shù)據庫存儲、contentprovider 內容提供者、網絡存儲。本文介紹了Android系統(tǒng)的五種數(shù)據存儲形式,有興趣的可以了解一下。
    2016-12-12
  • Android Canvas和Bitmap結合繪圖詳解流程

    Android Canvas和Bitmap結合繪圖詳解流程

    在 Android Canvas 上繪圖非常難,在繪圖時需要理解許多不同的類和概念。這篇文章中,將介紹 Android 框架中可用的一些類,它們可以讓畫布使用時更輕松
    2021-11-11
  • Flutter如何輕松實現(xiàn)動態(tài)更新ListView淺析

    Flutter如何輕松實現(xiàn)動態(tài)更新ListView淺析

    在Android中通常都會用到listview.那么flutter里面怎么用呢?下面這篇文章主要給大家介紹了關于Flutter如何輕松實現(xiàn)動態(tài)更新ListView的相關資料,需要的朋友可以參考下
    2022-02-02
  • Intent傳遞對象之Serializable和Parcelable的區(qū)別

    Intent傳遞對象之Serializable和Parcelable的區(qū)別

    Intent在不同的組件中傳遞對象數(shù)據的應用非常普遍,大家都知道在intent傳遞對象的方法有兩種:1、實現(xiàn)Serializable接口、2、實現(xiàn)Parcelable接口,接下來通過本文給大家介紹Intent傳遞對象之Serializable和Parcelable的區(qū)別,感興趣的朋友一起學習吧
    2016-01-01
  • android輸入框內容改變的監(jiān)聽事件實例

    android輸入框內容改變的監(jiān)聽事件實例

    下面小編就為大家分享一篇android輸入框內容改變的監(jiān)聽事件實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • Android Studio使用教程(一):下載與安裝及創(chuàng)建HelloWorld項目

    Android Studio使用教程(一):下載與安裝及創(chuàng)建HelloWorld項目

    這篇文章主要介紹了Android Studio使用教程(一):下載與安裝及創(chuàng)建HelloWorld項目,本文用詳細的圖文說明講解了Android Studio初步使用,需要的朋友可以參考下
    2015-05-05
  • Android中使用RecyclerView實現(xiàn)下拉刷新和上拉加載

    Android中使用RecyclerView實現(xiàn)下拉刷新和上拉加載

    RecyclerView 是Android L版本中新添加的一個用來取代ListView的SDK,它的靈活性與可替代性比listview更好。這篇文章主要介紹了Android中使用RecyclerView實現(xiàn)下拉刷新和上拉加載的相關資料,需要的朋友可以參考下
    2016-03-03
  • Android編程中Handler原理及用法實例分析

    Android編程中Handler原理及用法實例分析

    這篇文章主要介紹了Android編程中Handler用法,結合實例形式分析了Handler的功能,原理及使用技巧,需要的朋友可以參考下
    2016-01-01

最新評論