为了账号安全,请及时绑定邮箱和手机立即绑定

Retrofit2+Rxjava2联网的封装

标签:
Android

前言

开发过程中,一般都会对网络框架进行再次封装,以配置各种参数,并适合自己的编码风格。各种网络框架比较下来,还是Retrofit2+Rxjava2看着最爽,今天把这个东西整理了一下,发出来,示例给出了一般写法和MVP的写法。

Retrofit2+Rxjava2

Retrofit2Rxjava2基础的东西就不说了,直接进入主题。我们的需求是:

1、尽可能简洁
2、可控制不同请求的加载框,
3、错误统一处理
4、页面销毁时取消订阅
5、可根据不同请求处理不同的异常

先看一下最终的效果:

  Api.getDefaultService()
                .calendarBean("2017-06-29")
                .map(new RxFunction<Calendar>())
                .compose(RxSchedulers.<Calendar>io_main())
                .subscribe(new RxObserver<Calendar>(this, TAG, 0, false) {                    @Override
                    public void onSuccess(int whichRequest, Calendar calendar) {
                        tv_.setText(calendar.getLunar());
                    }                    @Override
                    public void onError(int whichRequest, Throwable e) {

                    }
                });

这个例子其中就包含了以上5点要求,其中大多是对RxObserver的处理。RxObserver实现Observer接口,在Rxjava2中作为观察者,在执行onNext之前先做一些处理,就能相应地减少在View层的处理。

    public RxObserver(Context context, String key, int whichRequest, boolean isShowDialog) {        this.mContext = context;        this.mKey = key;        this.isShowDialog = isShowDialog;        this.mWhichRequest = whichRequest;
        mDialog = new ProgressDialog(context);
        mDialog.setTitle("请稍后");

        mRxManager = RxManager.getInstance();
    }

参数说明: 
keykey是用来区分不同类中联网的CompositeDisposable的,以便在这个类销毁时,可以取消该类中订阅关系,建议采用包名+类名作为key,这个后面会详细说。 
whichRequest:区分不同的请求,用于多个联网请求结束后对不同请求的处理。 
isShowDialog:是否显示加载框,RxObserver内部实例化了一个加载框,可根据需求设置是否显示。

RxObserver实现了Observer的四个方法 void onSubscribe(@NonNull Disposable d);void onNext(@NonNull T t);void onError(@NonNull Throwable e);void onComplete();

    @Override
    public final void onSubscribe(Disposable d) {
        mRxManager.add(mKey, d);        if (isShowDialog) {
            mDialog.show();
        }
        onStart(mWhichRequest);
    }

onSubscribe(Disposable d)方法,相当于Rxjava1中的onStar()方法,其中的参数是Disposable ,用于取消该订阅关系,所以在方法中把它添加进了RxManager中,以方便取消订阅。同时也判断了isShowDialog了是否显示加载框,添加了一个方法onStart()方法,同时把mWhichRequest传出去方便在外部回调。

 @Override    public final void onNext(T value) {
        onSuccess(mWhichRequest, value);
    }

onNext(T value)方法比较简单,联网结果成功返回会执行,参数是结果。在这个方法中写了抽象方法onSuccess(mWhichRequest, value);同样把mWhichRequest传出,方便处理。

@Override
    public final void onComplete() {        if (mDialog.isShowing()) {
            mDialog.dismiss();
        }
    }

onComplete()方法是联网正常返回,联网过程结束时执行,在该方法中判断这个加载框的显示与否。

   @Override
    public final void onError(Throwable e) {        if (mDialog.isShowing()) {
            mDialog.dismiss();  
        }        if (e instanceof EOFException || e instanceof ConnectException || e instanceof SocketException || e instanceof BindException || e instanceof SocketTimeoutException || e instanceof UnknownHostException) {
            Toast.makeText(mContext, "网络异常,请稍后重试!", Toast.LENGTH_SHORT).show();
        } else if (e instanceof ApiException) {
            onError(mWhichRequest, e);
        } else {
            Toast.makeText(mContext, "未知错误!", Toast.LENGTH_SHORT).show();
        }
    }

onError(Throwable e)方法稍微复杂一些,整个过程出现异常是会执行这个方法,这里不只是联网的过程,还包括对返回数据处理上的异常,比如json解析失败等。如果发生异常就不会再走onComplete(),所以同样需要判断加载框的显示。下面的是对一些异常的处理,这里只处理了一些网络方面的异常,可以根据需求添加异常判断,这里处理的异常只是出现意外的异常。这里还自定义了一个异常ApiException,抛出这个异常都是业务上的问题,比如空数据,格式不对等等,这个是根据返回的状态值判断的,方便统一处理错误信息。

public class RxFunction<T> implements Function<HttpResult<T>, T> {
    @Override    public T apply(@NonNull HttpResult<T> httpResult) throws Exception {
        int retCode = httpResult.getRetCode();        if (retCode != 200) {            switch (retCode) {                case 21001:                    throw new ApiException("查询的日期格式错误,格式:yyyy-MM-dd");              //  case 2111:
              //      throw ........
            }
        }        return httpResult.getResult();
    }
}

这就是这个ApiException产生的地方,也是这句话map(new RxFunction<T>())用到的逻辑,这个是在Retrofit2解析json后得到HttpResult<T>,转化成Tmap操作符,在转化过程中根据HttpResult的状态值,判断是返回T还是抛出ApiException异常,这里可以根据返回状态值添加不同的错误提示信息,异常会在RxObserveronError(Throwable e)被捕捉,统一传到View层去处理。

compose(RxSchedulers.<Calendar>io_main())这句话是切换了一下线程,等同于这两句

.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())12

执行在io线程,表现在安卓主线程。RxSchedulers完整的代码:

public class RxSchedulers {    public static <T> ObservableTransformer<T, T> io_main() {        return new ObservableTransformer<T, T>() {
            @Override            public ObservableSource<T> apply( Observable<T> upstream) {                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }
}

还有一个类RxManager,这个类是用来管理订阅的,在RxObserver中,执行onSubscribe方法时,把参数Disposable添加进了RxManager中,看一下RxManager对应的add方法:

    public void add(String key, Disposable disposable) {        Set<String> keySet = map.keySet();        if (keySet.contains(key)) {
            CompositeDisposable compositeDisposable = map.get(key);
            compositeDisposable.add(disposable);
        } else {
            CompositeDisposable compositeDisposable = new CompositeDisposable();
            compositeDisposable.add(disposable);            map.put(key,compositeDisposable );
        }
    }

这里面,给每一个key初始化了一个CompositeDisposable并存入map,把这个Disposable 加入到对应的CompositeDisposable 中。

RxManager中还有一个方法clear(String key)

    public void clear(String key) {        Set<String> keySet = map.keySet();        if (keySet.contains(key)) {
            CompositeDisposable compositeDisposable = map.get(key);
            compositeDisposable.clear();            map.remove(key);
        }
    }

根据key得到对应的CompositeDisposable ,并执行compositeDisposable.clear()来取消compositeDisposable中所有的订阅关系。这个RxManagerclear方法建议放在BaseActivityonDestroy()方法中,这也是为什么前面说的建议这个key采用包名+类名的方式的原因,当这个类销毁的时候,该类中所有的联网订阅关系都会被取消,避免内存泄漏。为保证这个map唯一,RxManager采用了单利模式:

    private static RxManager rxManager;    private Map<String, CompositeDisposable> map;    private RxManager() {
        map = new HashMap<>();
    }    public static RxManager getInstance() {        if (rxManager == null) {
            rxManager = new RxManager();
        }        return rxManager;
    }

BaseActivity的onDestroy:

    @Override
    protected void onDestroy() {        super.onDestroy();
        RxManager.getInstance().clear(TAG);
    }

以上就是封装的netWork module的基本使用。 
最能体现Retrofit2+Rxjava2优势的自然是MVP的结构,下面就演示一下MVP的写法。

MVP

这里同样不讨论mvp的基础知识,也不讨论几种mvp哪种写法更正宗,我觉得只要是代码逻辑清楚,耦合性低,都是好的代码架构。 
这里为求简便,PresenterModel没有写成接口,直接写的各自的实现类。先看Model层:

public class MVPModel {    public Observable<Calendar> getCalendar(String date) {        return Api.getDefaultService().calendarBean(date).map(new RxFunction<Calendar>()).compose(RxSchedulers.<Calendar>io_main());
    }
}

Model切换线程,对请求的数据进行解析,并转化成我们需要的Observable<Calendar>对象。再看View层:

public interface MVPView {    void setResult(Calendar calendar);    void onError(int whichRequest ,Throwable t);    void onStartLoading(int whichRequest);    void onEndLoading(int whichRequest);

}

View需要写成接口,让对应的Activity或者Fragment去实现,View中除了setResultonError两个必要的方法外,又写了onStartLoadingonEndLoading两个方法,这两个方法是分别在联网操作开始和结束时候的回调,已满足其他需要在操作开始和结束做的操作,比如不用RxObserver中的加载框,需要其他加载框的,如如SwipeRefreshLayout。再看Presenter

public class MVPPresenter {

    private MVPModel mvpModel;    private MVPView mvpView;    public MVPPresenter(MVPView mvpView) {        this.mvpView = mvpView;
        mvpModel = new MVPModel();
    }    public void getCalendar(Context context,String date, String key,int whichRequest ,boolean isShowDialog) {

        mvpModel.getCalendar(date).subscribe(new RxObserver<Calendar>(context,key,whichRequest,isShowDialog) {            @Override
            public void onStart(int whichRequest) {                super.onStart(whichRequest);
                mvpView.onStartLoading(whichRequest);
            }            @Override
            public void onSuccess(int whichRequest, Calendar calendar) {
                mvpView.onEndLoading(whichRequest);
                mvpView.setResult(calendar);
            }            @Override
            public void onError(int whichRequest, Throwable e) {
                mvpView.onError(whichRequest, e);
                mvpView.onEndLoading(whichRequest);
            }
        });
    }
}

Presenter同时持有ModelView的对象,把从Model得到的数据传到View去处理。最后看View的实现类MVPActivity

public class MVPActivity extends BaseActivity implements MVPView{

    TextView tv_;    private MVPPresenter mvpPresenter;    @Override
    protected int getLayoutId() {        return R.layout.activity_mvp;
    }    @Override
    protected void initData() {
        tv_ = (TextView) findViewById(R.id.tv_);
        mvpPresenter = new MVPPresenter(this);
    }    public void request(View view) {
        mvpPresenter.getCalendar(this, "2018-10-01", TAG, 0, false);
    }    @Override
    public void setResult(Calendar calendar) {
        tv_.setText(calendar.getWeekday());
    }    /**
     * 如果有多个请求可根据whichRequest处理不同请求的异常
     * @param whichRequest
     * @param t
     */
    @Override
    public void onError(int whichRequest, Throwable t) {

    }    /**
     * 如果不使用RxObserver自带的Dialog,可以在RxObserver中设置false,
     * 在onStartLoading和onEndLoading设置需要其他dialog的显示和消失,如SwipeRefreshLayout
     * @param whichRequest
     */
    @Override
    public void onStartLoading(int whichRequest) {

    }    @Override
    public void onEndLoading(int whichRequest) {

    }
}

整个Activity看起来非常清爽,由mvpPresenter发出getCalendar()的请求,在setResult中获得结果,onError中处理异常,onStartLoadingonEndLoading处理加载框,如果一个页面需要多个请求,可以给RxObserver传入不同的whichRequest值,根据whichRequest判断在对应的方法中做不同的操作。

以上就是封装的这个Retrofit2+Rxjava2的全部内容了,例子中对Retrofit的配置不是很多,如果需要缓存等其他配置,可自行添加。

原文链接:http://www.apkbus.com/blog-865196-77236.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消