1,昨天咱們基本上把MVP給封裝起來了,今天接着昨天的東西來結合RxJava把Retrofit把網絡框架簡單的封裝一下,先看一下咱們今天實現的效果:java
哈哈 ,仍是昨天的效果,好吧 ,我認錯。android
2,因爲此次是把RxJava給接入進來了,因此咱們能夠對昨天的BasePresenter再次進行封裝api
BaseRxPresenter.java緩存
package com.qianmo.myview2.base; import rx.Subscription; import rx.subscriptions.CompositeSubscription; /** * Created by wangjitao on 2016/11/9 0009. * 基於Rx的Presenter的訂閱者的生命週期 */ public class BaseRxPresenter<T extends BaseView> implements BasePresenter<T> { protected T mView; protected CompositeSubscription mCompositeSubscription; protected void addSubscrebe(Subscription subscription) { if (mCompositeSubscription == null) { mCompositeSubscription = new CompositeSubscription(); } mCompositeSubscription.add(subscription); } protected void unSubscribe() { if (mCompositeSubscription != null) { mCompositeSubscription.unsubscribe(); } } @Override public void attachView(T view) { this.mView = view; } @Override public void detachView() { this.mView = null; unSubscribe(); } }
將View的綁定和解綁方法在這裏實現,並實現訂閱功能。網絡
先看一下咱們昨天沒有封裝的網絡請求app
Retrofit retrofit = new Retrofit.Builder() .baseUrl(Constant.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); AppVersionService movieService = retrofit.create(AppVersionService.class); movieService.getVersion() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<BaseResponse<VersionBean>>() { @Override public void onStart() { mView.showProgressDialog(); } @Override public void onCompleted() { mView.DissProgressDialog(); } @Override public void onError(Throwable e) { mView.DissProgressDialog(); mView.ShowToast("請求出錯"); } @Override public void onNext(BaseResponse<VersionBean> versionBeanBaseResponse) { if (Integer.valueOf(currentVersion.replace(".", "")) < Integer.valueOf(versionBeanBaseResponse.getData().getCode().replace(".", ""))) { // mView.showUpdateDialog(versionBean); //這裏表示發現新版本 mView.ShowToast("發現最新版本"); } else { //表示這就是最新版本 mView.ShowToast("已是最新版本"); } } });
由於這只是咱們的一個接口,若是是多個呢? 咱們每一次都要new一個Retrofit對象嗎? 而且每次要請求網絡的時候都要重寫Subscriber的這四個onstart()、onCompleted()、onError()、onNext(),通常咱們的Activity只關心最後的數據問題即它只想要咱們Presenter最後返回給它Bean的數據進行出來就行,其它一切東西它並非很想去只掉,好的,咱們就能夠幫它來解決這些問題框架
3,Retrofit的封裝ide
由上面的Retrofit咱們知道,咱們很不肯定的是retrofit.create方法,由於有可能咱們每次建立的APIService接口是不同的,因此這裏咱們能夠這樣封裝一下ui
public <T> T create(Class<T> service) { return mRetrofit.create(service); }
而後咱們每次並不想每次使用接口都去建立一個Retrofit對象,因此咱們可使用一個單例來解決this
private static RetrofitManager sInstace; /** * 私有構造方法 */ private RetrofitManager() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); if (BuildConfig.DEBUG) { // https://drakeet.me/retrofit-2-0-okhttp-3-0-config HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); builder.addInterceptor(loggingInterceptor); } File cacheFile = new File(Constant.PATH_CACHE); Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); Interceptor cacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!SystemUtil.isNetworkConnected()) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } Response response = chain.proceed(request); if (SystemUtil.isNetworkConnected()) { int maxAge = 0; // 有網絡時, 不緩存, 最大保存時長爲0 response.newBuilder() .header("Cache-Control", "public, max-age=" + maxAge) .removeHeader("Pragma") .build(); } else { // 無網絡時,設置超時爲4周 int maxStale = 60 * 60 * 24 * 28; response.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) .removeHeader("Pragma") .build(); } return response; } }; //設置緩存 builder.addNetworkInterceptor(cacheInterceptor); builder.addInterceptor(cacheInterceptor); builder.cache(cache); //設置超時 builder.connectTimeout(10, TimeUnit.SECONDS); builder.readTimeout(20, TimeUnit.SECONDS); builder.writeTimeout(20, TimeUnit.SECONDS); //錯誤重連 builder.retryOnConnectionFailure(true); mOkHttpClient = builder.build(); mRetrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(Constant.BASE_URL) .client(mOkHttpClient) .build(); } /** * 建立單例 */ public static RetrofitManager getInstace() { if (sInstace == null) { synchronized (RetrofitManager.class) { sInstace = new RetrofitManager(); } } return sInstace; }
能夠看到,再建立的時候咱們進行了一系列OkHttpClient和Retrofit的初始化,而後在上面的沒封裝的代碼中咱們每一都要寫
movieService.getVersion() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())
之類的代碼,因此咱們在提供一個方法在封裝一下
public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) { o.subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(s); }
ok,這樣咱們的RetrofitManager差很少就封裝完畢了,再看看完整的代碼
RetrofitManager.java
package com.qianmo.myview2.network; import android.content.Context; import android.provider.SyncStateContract; import com.qianmo.myview2.BuildConfig; import com.qianmo.myview2.api.ZhiHuApi; import com.qianmo.myview2.model.bean.DailyListBean; import com.qianmo.myview2.model.bean.ThemeListBean; import com.qianmo.myview2.utils.Constant; import com.qianmo.myview2.utils.SystemUtil; import java.io.File; import java.io.IOException; import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; import java.util.concurrent.TimeUnit; import okhttp3.Cache; import okhttp3.CacheControl; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; import rx.Observable; import rx.Subscriber; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; /** * Created by wangjitao on 2016/11/9 0009. * retrofit管理類 */ public class RetrofitManager { private static final int DEFAULT_TIMEOUT = 5; private Retrofit mRetrofit; private OkHttpClient mOkHttpClient; private static RetrofitManager sInstace; /** * 私有構造方法 */ private RetrofitManager() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); if (BuildConfig.DEBUG) { // https://drakeet.me/retrofit-2-0-okhttp-3-0-config HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); builder.addInterceptor(loggingInterceptor); } File cacheFile = new File(Constant.PATH_CACHE); Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); Interceptor cacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!SystemUtil.isNetworkConnected()) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } Response response = chain.proceed(request); if (SystemUtil.isNetworkConnected()) { int maxAge = 0; // 有網絡時, 不緩存, 最大保存時長爲0 response.newBuilder() .header("Cache-Control", "public, max-age=" + maxAge) .removeHeader("Pragma") .build(); } else { // 無網絡時,設置超時爲4周 int maxStale = 60 * 60 * 24 * 28; response.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) .removeHeader("Pragma") .build(); } return response; } }; //設置緩存 builder.addNetworkInterceptor(cacheInterceptor); builder.addInterceptor(cacheInterceptor); builder.cache(cache); //設置超時 builder.connectTimeout(10, TimeUnit.SECONDS); builder.readTimeout(20, TimeUnit.SECONDS); builder.writeTimeout(20, TimeUnit.SECONDS); //錯誤重連 builder.retryOnConnectionFailure(true); mOkHttpClient = builder.build(); mRetrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(Constant.BASE_URL) .client(mOkHttpClient) .build(); } /** * 建立單例 */ public static RetrofitManager getInstace() { if (sInstace == null) { synchronized (RetrofitManager.class) { sInstace = new RetrofitManager(); } } return sInstace; } public Retrofit getRetrofit() { return mRetrofit; } public <T> T create(Class<T> service) { return mRetrofit.create(service); } public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) { o.subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(s); } }
把Retrofit的建立給解決了咱們再看時解決每次重寫Subscriber的這四個onstart()、onCompleted()、onError()、onNext()的問題,因爲這一塊我以前的博客寫過的,就不給你們廢話了,只是大體的說一下思路了,建立一個ProgressSubscriber.java讓它繼承自Subscriber,並添加網絡請求時所須要的加載框,在onStart()方法中顯示加載框,在onCompleted()、onError()影藏加載框,再經過接口回調將onNext()中產生的數據回調給presenter中去通知UI更新就行,直接上代碼了
ProgressSubscriber.java
package com.qianmo.myview2.network; import android.content.Context; import android.widget.Toast; import java.net.ConnectException; import java.net.SocketTimeoutException; import rx.Subscriber; /** * Created by wangjitao on 2016/11/3 0003. */ public class ProgressSubscriber<T> extends Subscriber<T> implements ProgressCancelListener { private SubscriberOnNextListenter mSubscriberOnNextListenter; private ProgressDialogHandler mProgressDialogHandler; private Context context; public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) { this.mSubscriberOnNextListenter = mSubscriberOnNextListenter; this.context = context; mProgressDialogHandler = new ProgressDialogHandler(context, this, true); } /** * 在開始訂閱的時候顯示加載框 */ @Override public void onStart() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget(); } } /** * 在完成的時候進行隱藏 */ @Override public void onCompleted() { Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show(); dismissProgressDialog(); } /** * 在出錯的時候也進行影藏 * * @param e */ @Override public void onError(Throwable e) { if (e instanceof SocketTimeoutException) { Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態", Toast.LENGTH_SHORT).show(); } else if (e instanceof ConnectException) { Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } dismissProgressDialog(); } @Override public void onNext(T t) { mSubscriberOnNextListenter.next(t); } @Override public void onCancelProgress() { if (!this.isUnsubscribed()) { this.unsubscribe(); } } private void showProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget(); } } private void dismissProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget(); mProgressDialogHandler = null; } } }
ProgressDialogHandler.java
package com.qianmo.myview2.network; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.os.Message; /** * Created by liukun on 16/3/10. */ public class ProgressDialogHandler extends Handler { public static final int SHOW_PROGRESS_DIALOG = 1; public static final int DISMISS_PROGRESS_DIALOG = 2; private ProgressDialog pd; private Context context; private boolean cancelable; private ProgressCancelListener mProgressCancelListener; public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener, boolean cancelable) { super(); this.context = context; this.mProgressCancelListener = mProgressCancelListener; this.cancelable = cancelable; } private void initProgressDialog(){ if (pd == null) { pd = new ProgressDialog(context); pd.setCancelable(cancelable); if (cancelable) { pd.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { mProgressCancelListener.onCancelProgress(); } }); } if (!pd.isShowing()) { pd.show(); } } } private void dismissProgressDialog(){ if (pd != null) { pd.dismiss(); pd = null; } } @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW_PROGRESS_DIALOG: initProgressDialog(); break; case DISMISS_PROGRESS_DIALOG: dismissProgressDialog(); break; } } }
因爲咱們每次請求的時候有可能會出現一些請求的錯誤,,因此咱們這裏建立一個HttpResultFunc.java,來判斷此次請求是否成功
package com.qianmo.myview2.network; import com.qianmo.myview2.response.BaseResponse; import rx.functions.Func1; /** * Created by Administrator on 2016/11/9 0009. */ public class HttpResultFunc<T> implements Func1<BaseResponse<T>, T> { @Override public T call(BaseResponse<T> httpResult) { if (httpResult.getCode() != 200) { throw new ApiException(httpResult.getCode()); } return httpResult.getData(); } }
這樣基本上咱們的東西就封裝的差很少了,再看一下咱們的CheckVersion中調用代碼
Observable observable = RetrofitManager.getInstace() .create(AppVersionService.class).getVersion() .map(new HttpResultFunc<VersionBean>()); Subscription rxSubscription = new ProgressSubscriber<>(new SubscriberOnNextListenter<VersionBean>() { @Override public void next(VersionBean versionBean) { mView.setUpdateText(versionBean.getDes()); } }, context); RetrofitManager.getInstace().toSubscribe(observable, (Subscriber) rxSubscription); addSubscrebe(rxSubscription);
已經比較簡潔了(自我安慰中,小菜鳥畢竟技術有限),ok這樣網絡就大體的封裝好了,下一篇將Dagger加進來就差很少了
See You Next Time!