美文网首页面试题网络
MVVM在网络中封装(OkHttp+Retrofit+Gson+

MVVM在网络中封装(OkHttp+Retrofit+Gson+

作者: 像天空的鸽子 | 来源:发表于2019-08-26 19:39 被阅读0次
    封装目录结构

    1.首先安装类库

        api 'com.squareup.okhttp3:okhttp:3.11.0'
        api 'com.zhy:okhttputils:2.6.2'
        //Rxlifecycle
        api 'com.trello:rxlifecycle:0.3.1'
        api 'com.trello:rxlifecycle-components:0.3.1'
        api 'com.github.bumptech.glide:glide:4.8.0'
        api 'com.squareup.retrofit2:converter-gson:2.+'
        //必须使用
        api 'com.lzy.net:okgo:3.0.4'
        api 'com.squareup.okio:okio:1.5.0'
        api 'io.reactivex.rxjava2:rxjava:2.2.2'
        api 'io.reactivex.rxjava2:rxandroid:2.1.0'
        api 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.+'
        api 'com.squareup.retrofit2:retrofit:2.+'
        api 'com.squareup.okhttp3:logging-interceptor:3.11.0'
        api 'com.squareup.retrofit2:converter-gson:2.+'
        api 'com.squareup.retrofit2:converter-scalars:2.0.0'
        api 'com.facebook.stetho:stetho:1.4.2'
        api 'com.facebook.stetho:stetho-okhttp3:1.4.2'
        // 依赖以下两个库,会自动引用基础库与Android库
        api 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
        api 'com.trello.rxlifecycle2:rxlifecycle-navi:2.1.0'
        api 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'
        api 'com.jakewharton.rxbinding:rxbinding:1.+'
        // Lifecycles, LiveData 和 ViewModel
        //implementation "android.arch.lifecycle:runtime:1.0.0-alpha5"
        api "android.arch.lifecycle:extensions:1.1.0"
        // 对 RxJava 的支持
        api "android.arch.persistence.room:rxjava2:1.0.0-alpha5"
    

    2.创建常量类

    [——建议将这个类放在config文件夹——]
    
    package com.ylink.https.config;
    
    /**
     * 全局常量
     *
     * @author twilight
     * @Time 2019-07-21
     */
    
    public class HttpsConstant {
        /**
         * 请求后台的所有API接口都在这里配置;统一管理
         */
        public static class Server {
            //服务器超时时间 16 秒
            public final static int TIME_OUT = 30;
            //测试服务器地址
            public static final String ROOT_URL = "https://host:port/mobile-adapter/rest/merchant/app/"; //payapisit.fuxunpay.com
    //        public static final String ROOT_URL = "http://host:port/hibi-mobile-adapter/rest/merchant/app/";
        }
    
        /**
         * 服务器返回的状态码
         */
        public static class RespCode {
            //处理成功
            public static final String R000 = "R000";
            //登录超时
            public static final String R097 = "R097";
            //令牌无效
            public static final String R098 = "R098";
        }
        /**
         * 全局静态变量
         */
        public static class Param {
    
        }
    
        /**
         * sp 常量
         */
        public static class SP {
    
            public static final String SP = "sp";//sp
            public static final String SESSION_ID = "session_id";//
        }
        /**
         * 全局常量
         */
        public static class FINALVALUE {
    
        }
    }
    

    3.创建错误处理类

    [——建议将这个类放在exception文件夹——]
    
    package com.ylink.https.exception;
    
    /**
     * 前端自定义Exception
     */
    public class ApiException extends Exception {
        private String statusCode;//错误码
        private String statusDesc;//错误信息
    
        public ApiException(Throwable throwable, String statusCode) {
            super(throwable);
            this.statusCode = statusCode;
        }
    
        public ApiException(String statusCode, String statusDesc) {
            this.statusCode = statusCode;
            this.statusDesc = statusDesc;
        }
    
        public String getStatusCode() {
            return statusCode;
        }
    
        public void setStatusCode(String statusCode) {
            this.statusCode = statusCode;
        }
    
        public String getStatusDesc() {
            return statusDesc;
        }
    
        public void setStatusDesc(String statusDesc) {
            this.statusDesc = statusDesc;
        }
    }
    
    package com.ylink.https.exception;
    
    /**
     * 服务器返回的Exception
     */
    public class ServerException extends RuntimeException {
        private String statusCode;//错误码
        private String statusDesc;//错误信息
    
        public ServerException(String statusCode, String statusDesc) {
            this.statusCode = statusCode;
            this.statusDesc = statusDesc;
        }
    
        public String getStatusCode() {
            return statusCode;
        }
    
        public void setStatusCode(String statusCode) {
            this.statusCode = statusCode;
        }
    
        public String getStatusDesc() {
            return statusDesc;
        }
    
        public void setStatusDesc(String statusDesc) {
            this.statusDesc = statusDesc;
        }
    }
    
    package com.ylink.https.exception;
    
    import android.net.ParseException;
    import android.util.MalformedJsonException;
    
    import com.google.gson.JsonParseException;
    
    import org.json.JSONException;
    
    import java.net.ConnectException;
    import java.net.SocketTimeoutException;
    import java.net.UnknownHostException;
    
    import retrofit2.HttpException;
    
    public class ExceptionEngine {
        //客户端报错
        public static final int UN_KNOWN_ERROR = 9000;//未知错误
        public static final int ANALYTIC_SERVER_DATA_ERROR = 9001;//解析(服务器)数据错误
        public static final int ANALYTIC_CLIENT_DATA_ERROR = 9002;//解析(客户端)数据错误
        public static final int CONNECT_ERROR = 9003;//网络连接错误
        public static final int TIME_OUT_ERROR = 9004;//网络连接超时
        public static final int UNKNOWNHOSTEXCEPTION = 9005;//网络连接超时
    
        public static ApiException handleException(Throwable e) {
            ApiException ex;
            if (e instanceof HttpException) {             //HTTP错误
                HttpException httpExc = (HttpException) e;
                ex = new ApiException(e, String.valueOf(httpExc.code()));
                ex.setStatusDesc("网络错误,请稍后再试");  //均视为网络错误
                return ex;
            } else if (e instanceof ServerException) {    //服务器返回的错误
               ServerException serverExc = (ServerException) e;
                ex = new ApiException(serverExc, serverExc.getStatusCode());
                ex.setStatusDesc(serverExc.getStatusDesc());
                return ex;
            } else if (e instanceof JsonParseException
                    || e instanceof JSONException
                    || e instanceof ParseException || e instanceof MalformedJsonException) {  //解析数据错误
                ex = new ApiException(e, String.valueOf(ANALYTIC_SERVER_DATA_ERROR));
                ex.setStatusDesc("客户端异常,请稍后再试");
                return ex;
            } else if (e instanceof ConnectException) {//连接网络错误
                ex = new ApiException(e, String.valueOf(CONNECT_ERROR));
                ex.setStatusDesc("网络连接错误,请稍后再试");
                return ex;
            } else if (e instanceof SocketTimeoutException) {//网络超时
                ex = new ApiException(e, String.valueOf(TIME_OUT_ERROR));
                ex.setStatusDesc("网络连接超时,请稍后再试");
                return ex;
            }
            else if (e instanceof UnknownHostException) {//网络异常
                ex = new ApiException(e, String.valueOf(UNKNOWNHOSTEXCEPTION));
                ex.setStatusDesc("网络异常,请检查您的网络连接");
                return ex;
            }
            else {  //未知错误
                ex = new ApiException(e, String.valueOf(UN_KNOWN_ERROR));
                ex.setStatusDesc("系统异常,请稍后再试");
                return ex;
            }
        }
    
    }
    

    4.创建DTO、VO、Subscriber、Repository基类

    [——建议将这些类放在base文件夹——]
    
    package com.ylink.https.base;
    
    /**
     * 服务器返回公共实体
     *
     * @param <T>
     * @author twilight
     * @Time 2019-07-21
     */
    public class BaseDto<T> {
        private String statusCode;
        private String statusDesc;
        private T data;
    
        public String getStatusCode() {
            return statusCode;
        }
    
        public void setStatusCode(String statusCode) {
            this.statusCode = statusCode;
        }
    
        public String getStatusDesc() {
            return statusDesc;
        }
    
        public void setStatusDesc(String statusDesc) {
            this.statusDesc = statusDesc;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    
    package com.ylink.https.base;
    
    import java.io.Serializable;
    
    /**
     * 请求服务器的公共参数
     * 如果有需要可以在这添加公共参数
     *
     * @author twilight
     * @Time 2019-07-21
     */
    public class BaseVo implements Serializable {
    
    }
    
    package com.ylink.https.base;
    
    import android.arch.lifecycle.MutableLiveData;
    import android.content.Intent;
    import android.os.Handler;
    import android.util.Log;
    
    import com.ylink.commons.CommonsContext;
    import com.ylink.commons.config.CommonsConstant;
    import com.ylink.commons.utils.AppManager;
    import com.ylink.https.config.HttpsConstant;
    import com.ylink.https.exception.ApiException;
    import com.ylink.https.exception.ExceptionEngine;
    import com.ylink.https.exception.ServerException;
    
    import org.reactivestreams.Subscriber;
    import org.reactivestreams.Subscription;
    
    /**
     * 自定义请服务器被观察者
     *
     * @author twilight
     * @Time 2019-07-21
     */
    public class BaseHttpSubscriber<T> implements Subscriber<BaseDto<T>> {
    
        //异常类
        private ApiException ex;
    
        public BaseHttpSubscriber() {
            data = new MutableLiveData();
        }
    
        private MutableLiveData<BaseDto<T>> data;
    
        public MutableLiveData<BaseDto<T>> get() {
            return data;
        }
    
        public void set(BaseDto<T> t) {
            this.data.setValue(t);
        }
    
        public void onFinish(BaseDto<T> t) {
            set(t);
        }
    
        @Override
        public void onSubscribe(Subscription s) {
            // 观察者接收事件 = 1个
            s.request(1);
        }
    
        @Override
        public void onNext(BaseDto<T> t) {
            if (t.getStatusCode().equals(HttpsConstant.RespCode.R000)) {
                onFinish(t);
            } else if(t.getStatusCode().equals(HttpsConstant.RespCode.R097) || //登录超时,重新登录
                    t.getStatusCode().equals(HttpsConstant.RespCode.R098)){ //令牌无效
                CommonsContext.getInstance().reLogin();
                AppManager.getInstance().finishAllActivity();//结束所有页面
            } else{
                ex = ExceptionEngine.handleException(new ServerException(t.getStatusCode(), t.getStatusDesc()));
                getErrorDto(ex);
            }
        }
    
        @Override
        public void onError(Throwable t) {
            ex = ExceptionEngine.handleException(t);
            getErrorDto(ex);
        }
    
        /**
         * 初始化错误的dto
         *
         * @param ex
         */
        private void getErrorDto(ApiException ex) {
            BaseDto dto = new BaseDto();
            dto.setStatusCode(ex.getStatusCode());
            dto.setStatusDesc(ex.getStatusDesc());
            onFinish((BaseDto<T>) dto);
        }
    
        @Override
        public void onComplete() {
        }
    
    }
    
    package com.ylink.https.base;
    
    
    import io.reactivex.Flowable;
    import io.reactivex.android.schedulers.AndroidSchedulers;
    import io.reactivex.schedulers.Schedulers;
    
    /**
     * Repository基类
     *
     * @author twilight
     * @Time 2019-07-21
     */
    
    public class BaseRepository {
    
    
        /**
         * 请求网络
         * @param flowable
         * @param <T>
         * @return
         */
        public <T> BaseHttpSubscriber<T> request(Flowable<BaseDto<T>> flowable){
            BaseHttpSubscriber<T> baseHttpSubscriber = new BaseHttpSubscriber<>(); //RxJava Subscriber回调
            flowable.subscribeOn(Schedulers.io()) //解决背压
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(baseHttpSubscriber);
            return baseHttpSubscriber;
        }
    }
    

    5.创建拦截器

    [——建议将这个类放在interceptor文件夹——]
    
    package com.ylink.https.interceptor;
    
    import android.util.Log;
    
    import com.alibaba.fastjson.JSONObject;
    import com.ylink.commons.utils.SPUtil;
    import com.ylink.https.config.HttpsConstant;
    
    import java.io.IOException;
    import java.util.List;
    
    import okhttp3.Interceptor;
    import okhttp3.Request;
    import okhttp3.Response;
    
    /**
     * 自定义拦截器刷新sessionId  非首次请求的处理
     * @author twilight
     * @Time 2019-07-21
     */
    public class AddCookiesInterceptor implements Interceptor {
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request.Builder builder = chain.request().newBuilder();
            String cookieStr = SPUtil.getData(HttpsConstant.SP.SP, HttpsConstant.SP.SESSION_ID, String.class, null);
            List<String> cookies = JSONObject.parseArray(cookieStr, String.class);
            if (cookies != null) {
                for (String cookie : cookies) {
                    builder.addHeader("Cookie", cookie);
                    Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp
                }
            }
            return chain.proceed(builder.build());
        }
    }
    
    package com.ylink.https.interceptor;
    
    import com.alibaba.fastjson.JSONObject;
    import com.ylink.commons.utils.SPUtil;
    import com.ylink.https.config.HttpsConstant;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    import okhttp3.Interceptor;
    import okhttp3.Response;
    
    /**
     * 自定义拦截器刷新sessionId 首次请求的处理
     * @author twilight
     * @Time 2019-07-21
     */
    public class ReceivedCookiesInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
    
            Response originalResponse = chain.proceed(chain.request());
            if (!originalResponse.headers("Set-Cookie").isEmpty()) {
                List<String> cookies = new ArrayList<>();
                for (String header : originalResponse.headers("Set-Cookie")) {
                    cookies.add(header);
                }
                String cookieStr = JSONObject.toJSONString(cookies);
                SPUtil.putData(HttpsConstant.SP.SP, HttpsConstant.SP.SESSION_ID, cookieStr);
            }
    
            return originalResponse;
        }
    }
    

    6.创建请求类

    [——建议将这个类放在http文件夹——]
    
    package com.ylink.https.http;
    
    import android.util.Log;
    
    import com.facebook.stetho.okhttp3.StethoInterceptor;
    import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
    import com.ylink.https.config.HttpsConstant;
    import com.ylink.https.interceptor.AddCookiesInterceptor;
    import com.ylink.https.interceptor.ReceivedCookiesInterceptor;
    
    import java.util.concurrent.TimeUnit;
    
    import okhttp3.OkHttpClient;
    import okhttp3.logging.HttpLoggingInterceptor;
    import retrofit2.Retrofit;
    import retrofit2.converter.gson.GsonConverterFactory;
    
    /**
     * 普通的网络请求用到的Retrofit
     */
    
    public class RequetRetrofit {
        private static final String TAG = "RequetRetrofit";
         /**
         * 创建okhttp相关对象
         */
        private static OkHttpClient okHttpClient;
        /**
         * 创建Retrofit相关对象
         */
        private static Retrofit retrofit;
    
        public static <T> T getInstance(final Class<T> service) {
            if (okHttpClient == null) {
                synchronized (RequetRetrofit.class) {
                    if(okHttpClient == null) {
                        /**
                         * 创建okhttp相关对象
                         */
                        okHttpClient = new OkHttpClient.Builder()
    
                                .addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
                                    @Override
                                    public void log(String message) {   //访问网络请求,和服务端响应请求时。将数据拦截并输出
                                        Log.e(TAG, "log: " + message);
                                    }
                                }).setLevel(HttpLoggingInterceptor.Level.BODY))     //Log等级
                                .connectTimeout(HttpsConstant.Server.TIME_OUT, TimeUnit.SECONDS)       //超时时间
                                .readTimeout(HttpsConstant.Server.TIME_OUT, TimeUnit.SECONDS)
                                .writeTimeout(HttpsConstant.Server.TIME_OUT, TimeUnit.SECONDS)
                                .addNetworkInterceptor(new StethoInterceptor())
                                .addInterceptor(new AddCookiesInterceptor()) //
                                .addInterceptor(new ReceivedCookiesInterceptor())
                                .build();
                    }
                }
            }
    
            if (retrofit == null) {
                synchronized (RequetRetrofit.class) {
                    if(retrofit == null) {
                        retrofit = new Retrofit.Builder()
                                .baseUrl(HttpsConstant.Server.ROOT_URL)         //BaseUrl
                                .client(okHttpClient)                       //请求的网络框架
                                .addConverterFactory(GsonConverterFactory.create())     //解析数据格式
                                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 使用RxJava作为回调适配器
                                .build();
                    }
                }
            }
            return retrofit.create(service);
        }
    }
    

    相关文章

      网友评论

        本文标题:MVVM在网络中封装(OkHttp+Retrofit+Gson+

        本文链接:https://www.haomeiwen.com/subject/ozndectx.html