Android DevAndroid开发学习Weli收藏的文章Android

Rxjava2+Retrofit2+MVP的网络请求封装

2018-03-24  本文已影响1729人  果园_

一、概述

MVP的模式目前在网上已经层出不穷,大多数是通过接口建立关系,进行了功能的实现。看过很多类似的文章,受益良多。

下面切入正题,本文对异常的处理和订阅关系的动态取消进行了封装。通过泛型模式接通了MVP的三层关系。下面简单介绍组成体在本模式中的各个优点:

Retrofit2:通过注解的形式反射出请求体,像调用普通java方法一样的去获取请求对象,底层网络请求基于Okhttp3。

Rxjava2 : 便捷的线程调度,响应式编程,错误信息的简单追踪。

MVP:解耦,复用性好,代码清晰,易维护。

二、代码实现

代码结构目录
  1. 订阅关系的处理:网络请求不止一个,Rxjava2订阅关系就会很多,虽然Rxjava2内部实现了自动取消订阅关系(请求完成,请求报错),但是在特殊情况下需要手动关闭,在结束请求或者在应有的生命周期结束时订阅关系就要取消,比如在请求还没有结束的时候,View在没有执行完毕就退出了,那么它肯定不会自动解绑,这个时候就需要我们手动解除订阅关系,否则会产生内存泄漏。
import io.reactivex.disposables.Disposable;

public interface SubscriptionHelper<T> {
    void add(Disposable subscription);

    void cancel(Disposable t);

    void cancelall();
}

import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;

public class SubscriptionManager implements SubscriptionHelper<Object> {
    public static SubscriptionManager subscriptionManager;
    private CompositeDisposable mDisposables;

    public SubscriptionManager() {
        if (mDisposables == null) {
            mDisposables = new CompositeDisposable();
        }
    }

    @Override
    public void add(Disposable disposable) {
        if (disposable == null) return;
        mDisposables.add(disposable);
    }

    @Override
    public void cancel(Disposable disposable) {
        if (mDisposables != null) {
            mDisposables.delete(disposable);
        }
    }

    @Override
    public void cancelall() {
        if (mDisposables != null) {
            mDisposables.clear();
        }
    }

    public static SubscriptionManager getInstance() {
        if (subscriptionManager == null) {
            synchronized (SubscriptionManager.class) {
                if (subscriptionManager == null) {
                    subscriptionManager = new SubscriptionManager();
                }
            }
        }
        return subscriptionManager;
    }
}

2.网络请求异常的处理:针对常见网络请求异常进行了封装。

public class ErrorBodyDTO {
    private String errCode;
    private String errMsg;

    public String getErrCode() {
        return errCode;
    }

    public void setErrCode(String errCode) {
        this.errCode = errCode;
    }

    public String getErrMsg() {
        return errMsg;
    }

    public void setErrMsg(String errMsg) {
        this.errMsg = errMsg;
    }
}
import android.net.ParseException;

import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;

import org.json.JSONException;

import java.io.IOException;
import java.net.ConnectException;

import okhttp3.ResponseBody;

public class ExceptionHandle {
    private static final int UNAUTHORIZED = 401;
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;
    private static final int FAIL_QUEST = 406;//无法使用请求的内容特性来响应请求的网页
    private static final int BAD_REQUEST = 400;
    private static ResponseBody body;

    public static ResponeThrowable handleException(Throwable e) {
        ResponeThrowable ex;
        if (e instanceof HttpException) {
            HttpException httpException = (HttpException) e;
            ex = new ResponeThrowable(e, ERROR.HTTP_ERROR);
            switch (httpException.code()) {
                case UNAUTHORIZED:
                   /* body = ((HttpException) e).response().errorBody();
                    try {
                        String message = body.string();
                        Gson gson = new Gson();
                        Exception_401DTO exceptionDTO_401 = gson.fromJson(message, Exception_401DTO.class);
                        //[size=106 text={"error":"invalid_token","error_description":"Invalid access tok…]
                        if (exceptionDTO_401.getError().toString().equals("invalid_token")) {
                            ex.message = "请退出后登录";
                            //发出广播,然后跳转登录
                            ToLoginBean toLoginBean = new ToLoginBean();
                            toLoginBean.setFlag(true);
                            EventBus.getDefault().post(toLoginBean);
                        }
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }*/
                    break;
                case FORBIDDEN:
                    ex.message = "服务器已经理解请求,但是拒绝执行它";
                    break;
                case NOT_FOUND:
                    ex.message = "服务器异常,请稍后再试";
                    break;
                case REQUEST_TIMEOUT:
                    ex.message = "请求超时";
                    break;
                case GATEWAY_TIMEOUT:
                case INTERNAL_SERVER_ERROR:
                    ex.message = "服务器遇到了一个未曾预料的状况,无法完成对请求的处理";
                    break;
                case BAD_REQUEST:
                    /*body = ((HttpException) e).response().errorBody();
                    try {
                        String message = body.string();
                        Gson gson = new Gson();
                        Exception_401DTO exceptionDTO_401 = gson.fromJson(message, Exception_401DTO.class);
                        //[size=106 text={"error":"invalid_token","error_description":"Invalid access tok…]
                        *//**
                 * {"error":"invalid_grant","error_description":"Bad credentials"}
                 *//*
                        if (exceptionDTO_401.getError().toString().equals("invalid_grant")) {
                            ex.message = "用户名或密码错误";
                        }
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }*/
                    break;
                case BAD_GATEWAY:
                case SERVICE_UNAVAILABLE:
                case FAIL_QUEST:
                    body = ((HttpException) e).response().errorBody();
                    try {
                        String message = body.string();
                        Gson gson = new Gson();
                        ErrorBodyDTO globalExceptionDTO = gson.fromJson(message, ErrorBodyDTO.class);
                        if (globalExceptionDTO.getErrMsg() != null) {
                            ex.message = globalExceptionDTO.getErrMsg();
                        } else {
                            ex.message = "";
                        }
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    break;
                default:
                    ex.message = "网络错误";
                    break;
            }
            return ex;
        } else if (e instanceof ServerException) {
            ServerException resultException = (ServerException) e;
            ex = new ResponeThrowable(resultException, resultException.code);
            ex.message = resultException.message;
            return ex;
        } else if (e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException) {
            ex = new ResponeThrowable(e, ERROR.PARSE_ERROR);
            ex.message = "解析错误";
            return ex;
        } else if (e instanceof ConnectException) {
            ex = new ResponeThrowable(e, ERROR.NETWORD_ERROR);
            ex.message = "连接失败";
            return ex;
        } else if (e instanceof javax.net.ssl.SSLHandshakeException) {
            ex = new ResponeThrowable(e, ERROR.SSL_ERROR);
            ex.message = "证书验证失败";
            return ex;
        } else if (e instanceof java.net.SocketTimeoutException) {
            ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR);
            //ex.message = "连接超时";
            ex.message = "当前网络连接不顺畅,请稍后再试!";
            return ex;
        } else if (e instanceof java.net.UnknownHostException) {
            ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR);
            ex.message = "网络中断,请检查网络状态!";
            return ex;
        } else if (e instanceof javax.net.ssl.SSLException) {
            ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR);
            ex.message = "网络中断,请检查网络状态!";
            return ex;
        } else if (e instanceof java.io.EOFException) {
            ex = new ResponeThrowable(e, ERROR.PARSE_EmptyERROR);
            ex.message = "1007";
            return ex;
        } else if (e instanceof java.lang.NullPointerException) {
            ex = new ResponeThrowable(e, ERROR.PARSE_EmptyERROR);
            ex.message = "数据为空,显示失败";
            return ex;
        } else {
            ex = new ResponeThrowable(e, ERROR.UNKNOWN);
            ex.message = "未知错误";
            return ex;
        }
    }


    /**
     * 约定异常
     */
    public class ERROR {
        /**
         * 未知错误
         */
        public static final int UNKNOWN = 1000;
        /**
         * 解析错误
         */
        public static final int PARSE_ERROR = 1001;
        /**
         * 解析no content错误
         */
        public static final int PARSE_EmptyERROR = 1007;
        /**
         * 网络错误
         */
        public static final int NETWORD_ERROR = 1002;
        /**
         * 协议出错
         */
        public static final int HTTP_ERROR = 1003;

        /**
         * 证书出错
         */
        public static final int SSL_ERROR = 1005;

        /**
         * 连接超时
         */
        public static final int TIMEOUT_ERROR = 1006;

        public static final int LOGIN_ERROR = -1000;
        public static final int DATA_EMPTY = -2000;


    }

    public static class ResponeThrowable extends Exception {
        public int code;
        public String message;

        public ResponeThrowable(Throwable throwable, int code) {
            super(throwable);
            this.code = code;
        }

        public ResponeThrowable(String message, int code) {
            this.code = code;
            this.message = message;
        }
    }

    public class ServerException extends RuntimeException {
        public int code;
        public String message;

        public ServerException(int code, String message) {
            this.code = code;
            this.message = message;
        }
    }
}

3.Retrofit2请求体的创建。

import io.reactivex.Observable;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;
import utils.BeanGSchaxun;

public interface Apiservice {
    @GET("{fenzhi}{bianhao}/orderinfo")
    Observable<List<BeanGSchaxun>> getGSxin(@Path("fenzhi") String fenzhi,
                                            @Path("bianhao") String bianhao,
                                            @Query("batchNo") String batchNo);

}

4.RetrofitManager管理器的创建,保证Retrofit在类中只有一个实例,避免请求体的多次创建。

import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.neuqsoft.sipay.neuq.Mvp.Service.Apiservice;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitManager {
    private volatile static RetrofitManager retrofitManager;
    private Retrofit retrofit;

    //无参的单利模式
    public static RetrofitManager getSingleton() {
        if (retrofitManager == null) {
            synchronized (RetrofitManager.class) {
                retrofitManager = new RetrofitManager();
            }
        }
        return retrofitManager;
    }


    //无参的构造方法
    private RetrofitManager() {
        initRetrofitManager();
    }

    //构造方法创建Retrofit实例
    private void initRetrofitManager() {
        retrofit = new Retrofit.Builder().baseUrl("url" + "/")
                
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    public Apiservice Apiservice() {
        return retrofit.create(Apiservice.class);
    }
}

5.M层:业务逻辑的处理,实现了观察者中的方法,将其中请求的结果传递到抽象方法中,方便其他类的实现。(注意这里异常的传递和订阅关系的添加)

import java.util.List;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import utils.BeanGSchaxun;
import utils.houtai;

/**
 * Created by Gy 
 */

public class GsModel {

    public void getxinxi(String fenzhi, String bianhao, String shijian, Observer<List<BeanGSchaxun>> observer) {
        Observable<List<BeanGSchaxun>> gSxin = RetrofitManager.getSingleton().Apiservice().getGSxin(fenzhi, bianhao, shijian);
        gSxin.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(observer);

    }

}

import io.reactivex.disposables.Disposable;



public abstract class Observer<T> implements io.reactivex.Observer<T> {
    @Override
    public void onSubscribe(Disposable d) {
        //添加订阅关系
        OnDisposable(d);
    }

    @Override
    public void onNext(T t) {
        OnSuccess(t);
    }

    @Override
    public void onError(Throwable e) {
        //自定义异常的传递
        OnFail(ExceptionHandle.handleException(e));
    }

    @Override
    public void onComplete() {
        OnCompleted();
    }

    public abstract void OnSuccess(T t);

    public abstract void OnFail(ExceptionHandle.ResponeThrowable e);

    public abstract void OnCompleted();

    public abstract void OnDisposable(Disposable d);
}

6.MVP:这里就涉及到泛型的使用了。一般我们建立P和V层是通过实现接口的形式,这里通过泛型的类型规定来绑定我们的P和V。注意的一点是:我们的用户需要什么功能,V层接口就实现几个功能。因为是网络请求的封装,因此要有请求成功和请求失败。看代码(V层接口)。


//SimpleView——Activity里面要实现的方法在这里面定义
public interface SimpleView {
    void onSuccess(Object object);

    void onFail(ExceptionHandle.ResponeThrowable t);

    void OnCompleted();
}

然后V和P的关系建立,先创建基本的P层,它的作用是绑定和解除与V的关系。代码里面有注释。看代码(基本的P层)。

//<里面传入的参数必须是BaseView的子类或者本身>
//这个类的作用就是获取到当前的View
public class BasePresenter<V> {

    public V view;

    //加载View,建立连接
    public void addView(V v) {
        this.view = v;
    }

    //断开连接
    public void detattch() {
        if (view != null) {
            view = null;
        }
    }
}

import java.util.List;

import io.reactivex.disposables.Disposable;
import utils.BeanGSchaxun;
import utils.BeanGSlist;
import utils.BeanGsSecond;
import utils.BeanGsXiadan;


//(Presenter与View交互是通过接口),里面放一个接口
public class Gspresent extends BasePresenter<SimpleView> {
    private GsModel gsModel;

    public Gspresent() {
        gsModel = new GsModel();
    }

    //Presenter与View交互
    public void getGSxinxi(String fenzhi, String bianhao, String shijian) {
        gsModel.getxinxi(fenzhi, bianhao, shijian, new Observer<List<BeanGSchaxun>>() {
            @Override
            public void OnSuccess(List<BeanGSchaxun> beanGSchaxuns) {
                //继承关系,可以使用泛型里面的属性。
                view.onSuccess(beanGSchaxuns);

            }

            @Override
            public void OnFail(ExceptionHandle.ResponeThrowable e) {
                view.onFail(e);
            }

            @Override
            public void OnCompleted() {
                view.OnCompleted();
            }

            @Override
            public void OnDisposable(Disposable d) {
                SubscriptionManager.getInstance().add(d);
            }

        });
    }

}

我们分析下代码,这里涉及到泛型的使用。Gspresent继承BasePresenter<SimpleView>,那么子类就继承了BasePresenter和SimpleView的属性,这样就可以使用BasePresenter里面的变量view去调用SimpleView里面的方法。P和M层的关系建立通过New创建实例即可。
那么Activity的view是怎么传给P的呢?看下面代码。(MVPActivity)

import utils.BaseActivity;
//MvpActivity<P extends BasePresenter>:p继承了BasePresenter,就可以用P的参数去调用BasePresenter
//继承关系
public abstract class MvpActivity<p extends BasePresenter> extends BaseActivity {
    public p presener;

    @Override
    public void initBefore(Bundle savedInstanceState) {
        super.initBefore(savedInstanceState);
        presener = initPresener();
        //把所有继承此类的Activity都绑定到这里了,这样View就和Present联系起来了。
        presener.addView(this);
    }

    protected abstract p initPresener();

    @Override
    protected void onDestroy() {
        super.onDestroy();
        presener.detattch();
        //View消除时取消订阅关系
        SubscriptionManager.getInstance().cancelall();
    }
}

在基本的P层中看方法名就知道它是通过addview建立对外关系的,通过addview给view定义属性。这里面的泛型是BasePresenter(基本的P),调用泛型里面的属性方法 presener.addView(this)将Activity的上下文传赋值给view,这样P层就和Activity的View绑定到一起了。
MVPActivity建立了,使用的时候直接继承即可。

import java.util.List;

import butterknife.Bind;
import utils.Title;


public class WXPayEntryActivityc extends MvpActivity<Gspresent> implements SimpleView {

    @Bind(R.id.a)
    Title a;
    @Bind(R.id.xuanzetime)
    Button xuanzetime;
    @Bind(R.id.xinxi)
    Button xinxi;
    @Bind(R.id.time)
    TextView time;
    @Bind(R.id.next)
    Button next;
    @Bind(R.id.Gsxinxi)
    LinearLayout Gsxinxi;
    @Bind(R.id.lvGS)
    ListView lvGS;
    @Bind(R.id.scrollViewa)
    ScrollView scrollViewa;

    @Override
    public int getLayoutid() {
        return R.layout.activity_wxpay_entry_activityc;
    }


    @Override
    public void initView() {
    }

    @Override
    public void initData() {
    }


    @Override
    public void OnCompleted() {
    }

    @Override
    public void onSuccess(Object object) {
        if (object instanceof List) {
           //请求成功
        }

    }


    @Override
    public void onFail(ExceptionHandle.ResponeThrowable t) {
        Log.i(getPackageName(), t.message.toString());
        Toast.makeText(this, t.message.toString(), Toast.LENGTH_SHORT).show();
    }

    @Override
    protected Gspresent initPresener() {
        return new Gspresent();
    }

    }

这里面实现SimpleView 重写Onsuccess方法就可以拿到P层中请求的结果,而不用去做网络请求。

总结

使用泛型可以增加代码的扩展性。
MVP核心就是P层和V层的交互处理,根据V的需求定义P层接口。
欢迎大家的讨论。

上一篇下一篇

猜你喜欢

热点阅读