(四)安卓框架搭建之MVP+Retrofit+RxJava优化
来源:互联网 发布:淘宝零食店货源哪里来 编辑:程序博客网 时间:2024/05/18 03:05
BasePresenter的优化
RxJava也需要管理生命周期,即添加订阅和解除订阅。这里我们使之与presenter的addtachView()和detachView()同步,修改BasePresenter里面内容如下:
package com.example.burro.demo.appframework.mvp.presenter;import com.example.burro.demo.appframework.mvp.view.BaseView;import rx.Subscription;import rx.subscriptions.CompositeSubscription;/** * Presenter基类。目的是统一处理绑定和解绑 * Created by ex.zhong on 2017/9/23. */public class BasePresenter<T extends BaseView> implements IPresenter<T> { protected T mView; protected CompositeSubscription mCompositeSubscription; @Override public void attachView(T mView) { mView = mView; } @Override public void detachView() { mView = null; unSubscribe(); } //增加订阅者 protected void addSubscrebe(Subscription subscription) { if (mCompositeSubscription == null) { mCompositeSubscription = new CompositeSubscription(); } mCompositeSubscription.add(subscription); } //解绑订阅者 protected void unSubscribe() { if (mCompositeSubscription != null) { mCompositeSubscription.unsubscribe(); } }}
RetrofitManager的封装
看下先前TestPresenterImpl中的getMovieListData()内容,每次请求数据都重复新建一个Retrofit,绝对不能接受的,因此我们要对retrofit进行统一的封装,其中需使用单例模式。类中注释比较清楚,直接看下面内容:
package com.example.burro.demo.appframework.http;/** * Created by ex.zhong on 2017/9/24. */import com.example.burro.demo.appframework.BaseApplication;import com.example.burro.demo.appframework.util.FileUtils;import com.example.burro.demo.appframework.util.LogUtils;import com.example.burro.demo.appframework.util.NetWorkUtils;import java.io.File;import java.io.IOException;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;/** * retrofit封装方法 * Created by ex.zhong on 2017/8/13. */public class RetrofitManager { private static RetrofitManager instance; public static int MAXSTALE = 60 * 60 * 24 * 28; // 无网络时,设置超时为4周 public static int CONNECT_OUTTIME = 10; // 链接超时时间 unit:S public static int READ_OUTTIME = 20; // 读取数据超时时间 unit:S public static int WRITE_OUTTIME = 20; // 写入超时时间 unit:S public static long CACHE_SIZE = 1024*1024*50; // 缓存大小 50M private final OkHttpClient mOkHttpClient; private final Retrofit mRetrofit; /** * 创建单例 */ public static RetrofitManager getInstace() { if (instance == null) { synchronized (RetrofitManager.class) { instance = new RetrofitManager(); } } return instance; } /** * 获取retrofit */ public Retrofit getRetrofit() { return mRetrofit; } /** * 创建服务类 * @return */ public <T> T create(Class<T> service) { return mRetrofit.create(service); } /** * rx订阅 */ public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) { o.subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(s); } private RetrofitManager() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); //打印日志 if(LogUtils.LOG_FLAG){ // https://drakeet.me/retrofit-2-0-okhttp-3-0-config HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); builder.addInterceptor(loggingInterceptor); } //设置缓存 File cacheFile=new File(FileUtils.getInstance().getHttpCachePath()); Cache cache=new Cache(cacheFile,CACHE_SIZE); Interceptor cacheInterceptor=new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!NetWorkUtils.isOnline(BaseApplication.getAppContext())) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } Response response = chain.proceed(request); if (NetWorkUtils.isOnline(BaseApplication.getAppContext())) { int maxAge = 0; response.newBuilder() .header("Cache-Control", "public, max-age=" + maxAge) .removeHeader("Pragma") .build(); } else { 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(CONNECT_OUTTIME, TimeUnit.SECONDS); builder.readTimeout(READ_OUTTIME, TimeUnit.SECONDS); builder.writeTimeout(WRITE_OUTTIME, TimeUnit.SECONDS); //错误重连 builder.retryOnConnectionFailure(true); mOkHttpClient = builder.build(); mRetrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(HttpConfig.BASE_URL) .client(mOkHttpClient) .build(); }}
这里注意的是我把rxjava的订阅也放在了RetrofitManager内,这样不必每次在presenter实现类里重复的写下面方法
public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) { o.subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(s); }
Subscriber的封装
我们再看时解决每次重写Subscriber的这四个onstart()、onCompleted()、onError()、onNext()的问题,在此大致的说一下思路了,创建一个ProgressSubscriber.java让它继承自Subscriber,并添加网络请求时所需要的加载框,在onStart()方法中显示加载框【加载框我会传一个参数来控制是否需要加载】,在onCompleted()、onError()隐藏加载框,再通过接口回调将onNext()中产生的数据回调给presenter中去通知UI更新就行,
这里一共新建了5个类,如下:
ProgressCancelListener
主要是dialog取消时的回调时的接口,会在取消时执行解绑操作
package com.example.burro.demo.appframework.http;/*progressDialog,消失时回调 *Created by ex.zhong on 2017/9/25. */public interface ProgressCancelListener { void onCancelProgress();}
SubscriberOnResponseListenter
主要是Subscriber回调时封装的接口,即在回调中只处理onNext()onError()
package com.example.burro.demo.appframework.http;import com.example.burro.demo.dataframework.model.BaseResultBean;/**Subscriber回调,统一归结为next()【成功】 error()【失败】 * Created by ex.zhong on 2017/9/25 */public interface SubscriberOnResponseListenter<T> { void next(T t); void error(BaseResultBean t);}
ProgressDialogHandler
ProgressDialogHandler实为handler,内部主要控制dialog的显示和隐藏
package com.example.burro.demo.appframework.http;import android.content.Context;import android.content.DialogInterface;import android.content.DialogInterface.OnCancelListener;import android.os.Handler;import android.os.Message;import com.afollestad.materialdialogs.MaterialDialog;import com.afollestad.materialdialogs.Theme;/** 加载框展示,隐藏控制 * Created by ex.zhong on 2017/9/25. */public class ProgressDialogHandler extends Handler { public static final int SHOW_PROGRESS_DIALOG = 1; public static final int DISMISS_PROGRESS_DIALOG = 2; private Context context; private boolean cancelable; private ProgressCancelListener mProgressCancelListener; private MaterialDialog mProgressDialog; public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener, boolean cancelable) { super(); this.context = context; this.mProgressCancelListener = mProgressCancelListener; this.cancelable = cancelable; } //显示dialog private void initProgressDialog() { if (mProgressDialog == null) { mProgressDialog = new MaterialDialog.Builder(context) .canceledOnTouchOutside(cancelable) .content("正在加载...") .progress(true, 0) .theme(Theme.LIGHT) .build(); mProgressDialog.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { mProgressCancelListener.onCancelProgress(); } }); if (!mProgressDialog.isShowing()) { mProgressDialog.show(); } } } //隐藏dialog private void dismissProgressDialog() { if (mProgressDialog != null) { mProgressDialog.dismiss(); } } @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW_PROGRESS_DIALOG: initProgressDialog(); break; case DISMISS_PROGRESS_DIALOG: dismissProgressDialog(); break; } }}
ProgressSubscriber
ProgressSubscriber继承Subscriber,是对Subscriber的进一步封装,即在请求开始时提示dialog【可控制】,完成时,隐藏dialog等
package com.example.burro.demo.appframework.http;import android.content.Context;import android.net.ParseException;import com.example.burro.demo.dataframework.model.BaseResultBean;import com.google.gson.JsonParseException;import org.apache.http.conn.ConnectTimeoutException;import org.json.JSONException;import java.net.ConnectException;import java.net.SocketTimeoutException;import retrofit2.adapter.rxjava.HttpException;import rx.Subscriber;/** 并添加网络请求时所需要的加载框,异常情况统一处理 * Created by ex.zhong on 2017/9/25. */public class ProgressSubscriber<T> extends Subscriber<T> implements ProgressCancelListener { private SubscriberOnResponseListenter mSubscriberOnResponseListenter; private ProgressDialogHandler mProgressDialogHandler; private boolean isShowProgress; public ProgressSubscriber(SubscriberOnResponseListenter mSubscriberOnResponseListenter, Context context, boolean isShowProgress) { this.mSubscriberOnResponseListenter = mSubscriberOnResponseListenter; this.isShowProgress = isShowProgress; mProgressDialogHandler = new ProgressDialogHandler(context, this, false); } /** * 开始订阅的时候显示加载框 */ @Override public void onStart() { if (isShowProgress) showProgressDialog(); } @Override public void onCompleted() { dismissProgressDialog(); } @Override public void onError(Throwable e) { dismissProgressDialog(); BaseResultBean errorBean; //错误码要以服务器返回错误码为准。此处只是举例 if (e instanceof HttpException) { //HTTP 错误 HttpException httpException = (HttpException) e; switch (httpException.code()) { case BaseResultBean.ERROR_CODE_UNAUTHORIZED: errorBean = new BaseResultBean(BaseResultBean.ERROR_CODE_UNAUTHORIZED, "当前请求需要用户验证"); break; case BaseResultBean.ERROR_CODE_FORBIDDEN: errorBean = new BaseResultBean(BaseResultBean.ERROR_CODE_FORBIDDEN, "但是拒绝执行它"); break; case BaseResultBean.ERROR_CODE_NOT_FOUND: errorBean = new BaseResultBean(BaseResultBean.ERROR_CODE_NOT_FOUND, "服务器异常,请稍后再试"); break; default: //其它均视为网络错误 errorBean = new BaseResultBean(BaseResultBean.ERROR_CODE_FORBIDDEN, "网络错误"); break; } } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) { errorBean = new BaseResultBean(BaseResultBean.ERROR_CODE_PARSE_JSON, "解析错误"); } else if (e instanceof ConnectException || e instanceof SocketTimeoutException || e instanceof ConnectTimeoutException) { errorBean = new BaseResultBean(BaseResultBean.ERROR_CODE_NETWORK, "网络连接失败,请检查是否联网"); } else { errorBean = new BaseResultBean(BaseResultBean.ERROR_CODE_UNKNOWN, "未知错误"); } mSubscriberOnResponseListenter.error(errorBean); } //成功执行下一步 @Override public void onNext(T t) { mSubscriberOnResponseListenter.next(t); } @Override public void onCancelProgress() { if (!this.isUnsubscribed()) { this.unsubscribe(); } } //显示dialog private void showProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget(); } } //隐藏dialog private void dismissProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget(); } }}
HttpResultFunc
HttpResultFunc对返回的结果进行预处理。也是链式结构中重要的一环。具体请看注释:
package com.example.framework.appframework.http;import com.example.framework.dataframework.model.BaseResultBean;import rx.functions.Func1;/**预处理: * 由于我们每次请求的时候有可能会出现一些请求的错误, * 若返回码非正确,且服务器返回的错误信息可能是用户读不懂的信息。 * 比如豆瓣一个错误码1001 msg信息为uri_not_found,此时我们可以转换成用户可以读懂的文字,即可设置msg为“资源不存在” * Created by ex.zhong on 2017/9/25. */public class HttpResultFunc<T> implements Func1<T,T> { @Override public T call(T t) { if(t!=null&&t instanceof BaseResultBean){ int code=((BaseResultBean) t).getCode(); switch (code){ case 1001: ((BaseResultBean) t).setMessage("资源不存在"); break; case 1002: ((BaseResultBean) t).setMessage("参数不全"); break; //这里不再全部写出,实际根据情况写自己的业务处理 } } return t; }}
好了,封装部分全部结束,我们回头过来看看TestPresenterImpl
package com.example.burro.demo.appbiz.test;import android.content.Context;import com.example.burro.demo.appframework.http.HttpResultFunc;import com.example.burro.demo.appframework.http.ProgressSubscriber;import com.example.burro.demo.appframework.http.RetrofitManager;import com.example.burro.demo.appframework.http.SubscriberOnResponseListenter;import com.example.burro.demo.appframework.mvp.presenter.BasePresenter;import com.example.burro.demo.appbiz.test.TestContract.*;import com.example.burro.demo.appframework.util.StringUtils;import com.example.burro.demo.databiz.model.test.MovieListBean;import com.example.burro.demo.databiz.service.ApiService;import com.example.burro.demo.dataframework.model.BaseResultBean;import java.util.HashMap;import rx.Subscriber;import rx.Subscription;/**测试presenter * Created by ex.zhong on 2017/9/23. */public class TestPresenterImpl extends BasePresenter<View> implements Presenter { public TestPresenterImpl(Context mContext) { this.mContext = mContext; } @Override public void getMovieListData(int start, int count) { //获取数据 HashMap<String,String> map=new HashMap<>(); map.put("start", StringUtils.getString(start)); map.put("count", StringUtils.getString(count)); rx.Observable<MovieListBean> observable = RetrofitManager.getInstace().create(ApiService.class).getMovieListData(map).map((new HttpResultFunc<MovieListBean>())); Subscription rxSubscription = new ProgressSubscriber<>(new SubscriberOnResponseListenter<MovieListBean>() { @Override public void next(MovieListBean testBean) { mView.setMovieListData(testBean); } @Override public void error(BaseResultBean errResponse) { mView.showError(errResponse); } },mContext,false); RetrofitManager.getInstace().toSubscribe(observable, (Subscriber) rxSubscription); addSubscrebe(rxSubscription); }}
是不是简单了许多!!注意封装完以后要查看在TestActivity页面是否打印出请求结果!
相关链接
(五)安卓框架搭建之BaseFragment,MainActivity, Toolbar细化
github源码地址
- (四)安卓框架搭建之MVP+Retrofit+RxJava优化
- (三)安卓框架搭建之MVP+Retrofit+RxJava基础
- android MVP + dagger2 + Retrofit + Rxjava+okhttp android基础项目框架搭建(2)--之MVP引入
- 安卓开发框架(MVP+主流框架+基类+工具类)--- Retrofit+RxJava
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(一)
- 一步步搭建Retrofit+RxJava+MVP网络请求框架(一)
- Rxjava + retrofit + dagger2 + mvp搭建Android框架
- 搭建MVP+Retrofit+RxJava框架详解
- Retrofit+RXJava+MVP的框架搭建
- android MVP + dagger2 + Retrofit + Rxjava+okhttp android基础项目框架搭建(1)--之Dagger2引入
- RxJava+Retrofit+MVP框架
- Android Mvp快速搭建框架MVP+Dagger2+Retrofit+Rxjava
- 从0开始搭建rxjava+retrofit+mvp+dagger2整合基础框架(rxjava+retrofit网络层搭建)
- Android 一步步搭建MVP+Retrofit+RxJava网络请求框架
- Android 搭建MVP+Retrofit+RxJava网络请求框架
- MVP+Retrofit+RxJava+Dagger框架
- android MVP + dagger2 + Retrofit + Rxjava+okhttp android基础项目框架搭建(3)--完美实现
- 【BaseFragment】基于MVP+Dagger2+Retrofit+Rxjava框架之BaseFragment
- 自顶向下,逐步求精
- 机器学习的数学基础(1)——常见的函数与分布
- 解决Eclipse打开后无项目问题
- L
- 【算法】【Dynamic Programming】Unique Paths II
- (四)安卓框架搭建之MVP+Retrofit+RxJava优化
- sprongboot开发注意
- (五)安卓框架搭建之BaseFragment,MainActivity, Toolbar细化
- 汉诺塔问题
- MySQL数据库备份与恢复
- 设计模式之禅18
- Starship Troopers (树形dp+背包)
- (六)安卓框架搭建之RecyclerView和Adapter以及列表案例
- spark 机制原理自问自答