1,昨天我们基本上把MVP给封装起来了,今天接着昨天的东西来结合RxJava把Retrofit把网络框架简单的封装一下,先看一下我们今天实现的效果:
哈哈 ,还是昨天的效果,好吧 ,我认错。
2,由于这次是把RxJava给接入进来了,所以我们可以对昨天的BasePresenter再次进行封装
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 BaseRxPresenterimplements BasePresenter { 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的绑定和解绑方法在这里实现,并实现订阅功能。
先看一下我们昨天没有封装的网络请求
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>() { @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 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的封装
由上面的Retrofit我们知道,我们很不确定的是retrofit.create方法,因为有可能我们每次创建的APIService接口是不一样的,所以这里我们可以这样封装一下
publicT create(Class service) { return mRetrofit.create(service); }
然后我们每次并不想每次使用接口都去创建一个Retrofit对象,所以我们可以使用一个单例来解决
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())
之类的代码,所以我们在提供一个方法在封装一下
publicvoid toSubscribe(Observable o, Subscriber 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; } publicT create(Class service) { return mRetrofit.create(service); } public void toSubscribe(Observable o, Subscriber 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 ProgressSubscriberextends Subscriber 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 HttpResultFuncimplements Func1 , T> { @Override public T call(BaseResponse 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()); Subscription rxSubscription = new ProgressSubscriber<>(new SubscriberOnNextListenter () { @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!