日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

去年的時候?qū)W習(xí)了RxJAVA和Retrofit的基本用法,但一直沒有在實際項目中運用。今年開做新項目,果斷在新項目中引入了RxJava和Retrofit。本篇文章將介紹筆者在項目中對Retrofit的封裝。

先來看一下封裝過后的Retrofit如何使用。

RetrofitHelper.getApiService()
 .getMezi()
 .compose(this.<List<MeiZi>>bindToLifecycle())
 .compose(ProgressUtils.<List<MeiZi>>ApplyProgressBar(this))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(new DefaultObserver<List<MeiZi>>() {
 @Override
 public void onSuccess(List<MeiZi> response) {
 showToast("請求成功,妹子個數(shù)為" + response.size());
 }
 });

沒錯,就是這么簡潔的一個鏈?zhǔn)秸{(diào)用,可以顯示加載動畫,還加入了Retrofit生命周期的管理。

開始之前需要先在module項目里的Gradle文件中添加用到的依賴庫

 compile "io.reactivex.rxjava2:rxjava:$rootProject.ext.rxjava2Version"
 compile "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofit2Version"
 compile "com.squareup.retrofit2:converter-scalars:$rootProject.ext.retrofit2Version"
 compile "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofit2Version"
 compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.ext.retrofit2Version"
 compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
 compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
 compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
 compile "com.trello.rxlifecycle2:rxlifecycle:$rootProject.ext.rxlifecycle"
 //compile "com.trello.rxlifecycle2:rxlifecycle-android:$rootProject.ext.rxlifecycle"
 compile "com.trello.rxlifecycle2:rxlifecycle-components:$rootProject.ext.rxlifecycle"

為了方便依賴庫版本的修改我們采用”io.reactivex.rxjava2:rxjava:$rootProject.ext.rxjava2Version”這中方式添加依賴,因此需要在project的build.gradle文件的加上以下內(nèi)容:

ext {
 supportLibVersion = '25.1.0'
 butterknifeVersion = '8.5.1'
 rxjava2Version = '2.0.8'
 retrofit2Version = '2.2.0'
 rxlifecycle='2.1.0'
 gsonVersion = '2.8.0'
}

下面將通過幾個小節(jié)對本次封裝作詳細(xì)的解析:

  • 服務(wù)器響應(yīng)數(shù)據(jù)的基類BasicResponse
  • 構(gòu)建初始化Retrofit的工具類IdeaApi
  • 通過GsonConverterFactory獲取真實響應(yīng)數(shù)據(jù)
  • 封裝DefaultObserver處理服務(wù)器響應(yīng)
  • 處理加載Loading
  • 管理Retrofit生命周期
  • 如何使用封裝
  • 小結(jié)

一.服務(wù)器響應(yīng)數(shù)據(jù)的基類BasicResponse。

假定服務(wù)器返回的Json數(shù)據(jù)格式如下:

{
 "code": 200,
 "message": "成功",
 "content": {
 ...
 }
}

根據(jù)Json數(shù)據(jù)格式構(gòu)建我們的BasicResponse(BasicResponse中的字段內(nèi)容需要根據(jù)自己服務(wù)器返回的數(shù)據(jù)確定)。代碼如下:

public class BasicResponse<T> {
 private int code;
 private String message;
 private T content;
 ...此處省去get、set方法。

二.構(gòu)建初始化Retrofit的工具類IdeaApi。

該類通過RetrofitUtils來獲取ApiService的實例。代碼如下:

public class IdeaApi {
 public static <T> T getApiService(Class<T> cls,String baseUrl) {
 Retrofit retrofit = RetrofitUtils .getRetrofitBuilder(baseUrl).build();
 return retrofit.create(cls);
 }
}

RetrofitUtils用來構(gòu)建Retrofit.Builder,并對OkHttp做以下幾個方面的配置:

  1. 設(shè)置日志攔截器,攔截服務(wù)器返回的json數(shù)據(jù)。Retrofit將請求到j(luò)son數(shù)據(jù)直接轉(zhuǎn)換成了實體類,但有時候我們需要查看json數(shù)據(jù),Retrofit并沒有提供直接獲取json數(shù)據(jù)的功能。因此我們需要自定義一個日志攔截器攔截json數(shù)據(jù),并輸入到控制臺。
  2. 設(shè)置Http請求頭。給OkHttp 添加請求頭攔截器,配置請求頭信息。還可以為接口統(tǒng)一添加請求頭數(shù)據(jù)。例如,把用戶名、密碼(或者token)統(tǒng)一添加到請求頭。后續(xù)每個接口的請求頭中都會攜帶用戶名、密碼(或者token)數(shù)據(jù),避免了為每個接口單獨添加。
  3. 為OkHttp配置緩存。同樣可以同過攔截器實現(xiàn)緩存處理。包括控制緩存的最大生命值,控制緩存的過期時間。
  4. 如果采用https,我們還可以在此處理證書校驗以及服務(wù)器校驗。
  5. 為Retrofit添加GsonConverterFactory。此處是一個比較重要的環(huán)節(jié),將在后邊詳細(xì)講解。

RetrofitUtils 代碼如下:

public class RetrofitUtils {
 public static OkHttpClient.Builder getOkHttpClientBuilder() {
 HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
 @Override
 public void log(String message) {
 try {
 LogUtils.e("OKHttp-----", URLDecoder.decode(message, "utf-8"));
 } catch (UnsupportedEncodingException e) {
 e.printStackTrace();
 LogUtils.e("OKHttp-----", message);
 }
 }
 });
 loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
 File cacheFile = new File(Utils.getContext().getCacheDir(), "cache");
 Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb
 return new OkHttpClient.Builder()
 .readTimeout(Constants.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
 .connectTimeout(Constants.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
 .addInterceptor(loggingInterceptor)
 .addInterceptor(new HttpHeaderInterceptor())
 .addNetworkInterceptor(new HttpCacheInterceptor())
 // .sslSocketFactory(SslContextFactory.getSSLSocketFactoryForTwoWay()) // https認(rèn)證 如果要使用https且為自定義證書 可以去掉這兩行注釋,并自行配制證書。
 // .hostnameVerifier(new SafeHostnameVerifier())
 .cache(cache);
 }
 public static Retrofit.Builder getRetrofitBuilder(String baseUrl) {
 Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create();
 OkHttpClient okHttpClient = RetrofitUtils.getOkHttpClientBuilder().build();
 return new Retrofit.Builder()
 .client(okHttpClient)
 .addConverterFactory(GsonConverterFactory.create(gson))
 .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
 .baseUrl(baseUrl);
 }
}

三.通過GsonConverterFactory獲取真實響應(yīng)數(shù)據(jù)

在第一節(jié)中我們構(gòu)建了服務(wù)器響應(yīng)數(shù)據(jù)BasicResponse,BasicResponse由code、message、和content三個字段。其中code為服務(wù)器返回的錯誤碼。我們會事先和服務(wù)器約定成功時的code值,比如200表示請求成功。但通常在請求服務(wù)器數(shù)據(jù)過程中免不了會出現(xiàn)各種錯誤。例如用戶登錄時密碼錯誤、請求參數(shù)錯誤的情況。此時服務(wù)器會根據(jù)錯誤情況返回對應(yīng)的錯誤碼。一般來說,我們只關(guān)心成功時即code為200時的content數(shù)據(jù)。而對于code不為200時我們只需要給出對應(yīng)的Toast提示即可。事實上我們對我們有用的僅僅時code為200時的content數(shù)據(jù)。因此我們可以考慮過濾掉code和message,在請求成功的回調(diào)中只返回content的內(nèi)容。

在此種情況下就需要我們通過自定義GsonConverterFactory來實現(xiàn)了。我們可以直接從Retrofit的源碼中copy出GsonConverterFactory的三個相關(guān)類來做修改。

其中最終要的一部分是修改GsonResponseBodyConverter中的convert方法。在該方法中拿到服務(wù)器響應(yīng)數(shù)據(jù)并判斷code是否為200。如果是,則獲取到content并返回,如果不是,則在此處可以拋出對應(yīng)的自定義的異常。然后再Observer中統(tǒng)一處理異常情況。GsonResponseBodyConverter代碼如下:

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, Object> {
 private final TypeAdapter<T> adapter;
 GsonResponseBodyConverter(TypeAdapter<T> adapter) {
 this.adapter = adapter;
 }
 @Override
 public Object convert(ResponseBody value) throws IOException {
 try {
 BasicResponse response = (BasicResponse) adapter.fromJson(value.charStream());
 if (response.getCode()==200) {
 return response.getResults();
 } else {
 // 特定 API 的錯誤,在相應(yīng)的 DefaultObserver 的 onError 的方法中進(jìn)行處理
 throw new ServerResponseException(response.getCode(), response.getMessage());
 }
 } finally {
 value.close();
 }
 return null;
 }
}

四.構(gòu)建DefaultObserver處理服務(wù)器響應(yīng)。

上一節(jié)中我們講到了在請求服務(wù)器時可能出現(xiàn)的一些例如密碼錯誤、參數(shù)錯誤的情況,服務(wù)器給我們返回了對應(yīng)的錯誤碼,我們根據(jù)錯誤碼拋出了對應(yīng)自定義異常。除此之外在我們發(fā)起網(wǎng)絡(luò)請求時還可能發(fā)生一些異常情況。例如沒有網(wǎng)絡(luò)、請求超時或者服務(wù)器返回了數(shù)據(jù)但在解析時出現(xiàn)了數(shù)據(jù)解析異常等。對于這樣的情況我們也要進(jìn)行統(tǒng)一處理的。那么我們就需要自定義一個DefaultObserver類繼承Observer,并重寫相應(yīng)的方法。

該類中最重要的兩個方法時onNext和onError。

1.在服務(wù)器返回數(shù)據(jù)成功的情況下會回調(diào)到onNext方法。因此我們可以在DefaultObserver中定義一個抽象方法onSuccess(T response),在調(diào)用網(wǎng)絡(luò)時重寫onSuccess方法即可。

2.如果在請求服務(wù)器過程中出現(xiàn)任何異常,都會回調(diào)到onError方法中。包括上節(jié)中我們自己拋出的異常都會回調(diào)到onError。因此我們的重頭戲就是處理onError。在onError中我們根據(jù)異常信息給出對應(yīng)的Toast提示即可。

DefaultObserver類的代碼如下:

public abstract class DefaultObserver<T> implements Observer<T> {
 @Override
 public void onSubscribe(Disposable d) {
 }
 @Override
 public void onNext(T response) {
 onSuccess(response);
 onFinish();
 }
 @Override
 public void onError(Throwable e) {
 LogUtils.e("Retrofit", e.getMessage());
 if (e instanceof HttpException) { // HTTP錯誤
 onException(ExceptionReason.BAD_NETWORK);
 } else if (e instanceof ConnectException
 || e instanceof UnknownHostException) { // 連接錯誤
 onException(ExceptionReason.CONNECT_ERROR);
 } else if (e instanceof InterruptedIOException) { // 連接超時
 onException(ExceptionReason.CONNECT_TIMEOUT);
 } else if (e instanceof JsonParseException
 || e instanceof JSONException
 || e instanceof ParseException) { // 解析錯誤
 onException(ExceptionReason.PARSE_ERROR);
 }else if(e instanceof ServerResponseException){
 onFail(e.getMessage());
 } else {
 onException(ExceptionReason.UNKNOWN_ERROR);
 }
 onFinish();
 }
 @Override
 public void onComplete() {
 }
 /**
 * 請求成功
 *
 * @param response 服務(wù)器返回的數(shù)據(jù)
 */
 abstract public void onSuccess(T response);
 /**
 * 服務(wù)器返回數(shù)據(jù),但響應(yīng)碼不為200
 *
 */
 public void onFail(String message) {
 ToastUtils.show(message);
 }
 public void onFinish(){}
 /**
 * 請求異常
 *
 * @param reason
 */
 public void onException(ExceptionReason reason) {
 switch (reason) {
 case CONNECT_ERROR:
 ToastUtils.show(R.string.connect_error, Toast.LENGTH_SHORT);
 break;
 case CONNECT_TIMEOUT:
 ToastUtils.show(R.string.connect_timeout, Toast.LENGTH_SHORT);
 break;
 case BAD_NETWORK:
 ToastUtils.show(R.string.bad_network, Toast.LENGTH_SHORT);
 break;
 case PARSE_ERROR:
 ToastUtils.show(R.string.parse_error, Toast.LENGTH_SHORT);
 break;
 case UNKNOWN_ERROR:
 default:
 ToastUtils.show(R.string.unknown_error, Toast.LENGTH_SHORT);
 break;
 }
 }
 /**
 * 請求網(wǎng)絡(luò)失敗原因
 */
 public enum ExceptionReason {
 /**
 * 解析數(shù)據(jù)失敗
 */
 PARSE_ERROR,
 /**
 * 網(wǎng)絡(luò)問題
 */
 BAD_NETWORK,
 /**
 * 連接錯誤
 */
 CONNECT_ERROR,
 /**
 * 連接超時
 */
 CONNECT_TIMEOUT,
 /**
 * 未知錯誤
 */
 UNKNOWN_ERROR,
 }
}

五.處理加載Loading

關(guān)于Loading我們可以通過RxJava的compose操作符來做一個非常優(yōu)雅的處理。首先定義一個ProgressUtils工具類,然后通過RxJava的ObservableTransformer做一個變換來處理Loading。想要顯示Loading,只需要加上.compose(ProgressUtils.< T >applyProgressBar(this))即可。

ProgressUtils代碼如下:

public class ProgressUtils {
 public static <T> ObservableTransformer<T, T> applyProgressBar(
 @NonNull final Activity activity, String msg) {
 final WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);
 final DialogUtils dialogUtils = new DialogUtils();
 dialogUtils.showProgress(activityWeakReference.get());
 return new ObservableTransformer<T, T>() {
 @Override
 public ObservableSource<T> apply(Observable<T> upstream) {
 return upstream.doOnSubscribe(new Consumer<Disposable>() {
 @Override
 public void accept(Disposable disposable) throws Exception {
 }
 }).doOnTerminate(new Action() {
 @Override
 public void run() throws Exception {
 Activity context;
 if ((context = activityWeakReference.get()) != null
 && !context.isFinishing()) {
 dialogUtils.dismissProgress();
 }
 }
 }).doOnSubscribe(new Consumer<Disposable>() {
 @Override
 public void accept(Disposable disposable) throws Exception {
 /*Activity context;
 if ((context = activityWeakReference.get()) != null
 && !context.isFinishing()) {
 dialogUtils.dismissProgress();
 }*/
 }
 });
 }
 };
 }
 public static <T> ObservableTransformer<T, T> applyProgressBar(
 @NonNull final Activity activity) {
 return applyProgressBar(activity, "");
 }
}

至此關(guān)于RxJava和Retrofit的二次封裝已經(jīng)基本完成。但是我們不能忽略了很重要的一點,就是網(wǎng)絡(luò)請求的生命周期。我們將在下一節(jié)中詳細(xì)講解。

## 六、管理Retrofit生命周期

當(dāng)activity被銷毀時,網(wǎng)絡(luò)請求也應(yīng)該隨之終止的。要不然就可能造成內(nèi)存泄漏。會嚴(yán)重影到響App的性能!因此Retrofit生命周期的管理也是比較重要的一點內(nèi)容。在這里我們使用 RxLifecycle來對Retrofit進(jìn)行生命周期管理。其使用流程如下:

1.在gradel中添加依賴如下:

compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0'
compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'

2.讓我們的BaseActivity繼承RxAppCompatActivity。

具體代碼如下:

public abstract class BaseActivity extends RxAppCompatActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(getLayoutId());
 init(savedInstanceState);
 }
 protected void showToast(String msg) {
 ToastUtils.show(msg);
 }
 protected abstract @LayoutRes int getLayoutId();
 protected abstract void init(Bundle savedInstanceState);
}

同樣我們項目的BaseFragment繼承RxFragment(注意使用繼承V4包下的RxFragment),如下:

public abstract class BaseFragment extends RxFragment {
 public View rootView;
 public LayoutInflater inflater;
 @Nullable
 @Override
 public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 super.onCreateView(inflater, container, savedInstanceState);
 this.inflater = inflater;
 if (rootView == null) {
 rootView = inflater.inflate(this.getLayoutId(), container, false);
 init(savedInstanceState);
 }
 ViewGroup parent = (ViewGroup) rootView.getParent();
 if (parent != null) {
 parent.removeView(rootView);
 }
 return rootView;
 }
 protected abstract int getLayoutId();
 protected abstract void init(Bundle savedInstanceState);
 protected void showToast(String msg) {
 ToastUtils.show(msg);
 }
 @Override
 public void onResume() {
 super.onResume();
 }
 @Override
 public void onPause() {
 super.onPause();
 }
 @Override
 public void onDestroyView() {
 super.onDestroyView();
 }
}

3.使用compose操作符管理Retrofit生命周期了:

myObservable
 .compose(bindToLifecycle())
 .subscribe();
或者
myObservable
 .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
 .subscribe();

關(guān)于RxLifecycle的詳細(xì)使用方法可以參考 RxLifecycle官網(wǎng)

七.如何使用封裝

前面幾節(jié)內(nèi)容講解了如何RxJava進(jìn)行二次封裝,封裝部分的代碼可以放在我們項目的Library模塊中。那么封裝好之后我們應(yīng)該如何在app模塊中使用呢?

1.定義一個接口來存放我們項目的API

public interface IdeaApiService {
 /**
 * 此接口服務(wù)器響應(yīng)數(shù)據(jù)BasicResponse的泛型T應(yīng)該是List<MeiZi>
 * 即BasicResponse<List<MeiZi>>
 * @return BasicResponse<List<MeiZi>>
 */
 @Headers("Cache-Control: public, max-age=10")//設(shè)置緩存 緩存時間為100s
 @GET("福利/10/1")
 Observable<List<MeiZi>> getMezi();
 /**
 * 登錄 接口為假接口 并不能返回數(shù)據(jù)
 * @return
 */
 @POST("login.do")
 Observable<LoginResponse> login(@Body LoginRequest request);
 /**
 * 刷新token 接口為假接口 并不能返回數(shù)據(jù)
 * @return
 */
 @POST("refresh_token.do")
 Observable<RefreshTokenResponseBean> refreshToken(@Body RefreshTokenRequest request);
 @Multipart
 @POST("upload/uploadFile.do")
 Observable<BasicResponse> uploadFiles(@Part List<MultipartBody.Part> partList);
}

2.定義一個RetrofitHelper 類,通過IdeaApi來獲取IdeaApiService的實例。

public class RetrofitHelper {
 private static IdeaApiService mIdeaApiService;
 public static IdeaApiService getApiService(){
 return mIdeaApiService;
 }
 static {
 mIdeaApiService= IdeaApi.getApiService(IdeaApiService.class, Constants.API_SERVER_URL);
 }
}

3.在Activity或者Fragment中發(fā)起網(wǎng)絡(luò)請求

 /**
 * Get請求
 * @param view
 */
 public void getData(View view) {
 RetrofitHelper.getApiService()
 .getMezi()
 .compose(this.<List<MeiZi>>bindToLifecycle())
 .compose(ProgressUtils.<List<MeiZi>>applyProgressBar(this))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(new DefaultObserver<List<MeiZi>>() {
 @Override
 public void onSuccess(List<MeiZi> response) {
 showToast("請求成功,妹子個數(shù)為" + response.size());
 }
 });
 }

八.小結(jié)

本篇文章主要講解了Rxjava和Retrofit的二次封裝。以上內(nèi)容也是筆者參考多方面的資料經(jīng)過長時間的改動優(yōu)化而來。但鑒于本人能力有限,其中也避免不了出現(xiàn)不當(dāng)之處。還請大家多多包涵。另外,在投稿郭神公眾號時文章可能還存在很多處理不優(yōu)雅的地方,比如對響應(yīng)數(shù)據(jù)的處理以及對Loading的處理。在投稿被推送后收到了很多小伙伴的建議,因此筆者也參考了大家的意見并做了優(yōu)化,在此感謝大家。最后如果有疑問歡迎在文章留言評論。

分享到:
標(biāo)簽:封裝 Android
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定