美文网首页Android收藏集Androidrxjava
优雅封装Retrofit+RxJava联网的统一管理类

优雅封装Retrofit+RxJava联网的统一管理类

作者: 一只懂音乐的码虫 | 来源:发表于2018-05-02 14:54 被阅读650次

    Retrofit的简单用法在上一篇文章分分钟使用Retrofit+Rxjava实现网络请求已经做过介绍了,今天就不赘述了。
    今天主要分享一下如何结合Rxjava,封装一个RetrofitManager管理类,统一管理联网操作。

    《一》让我们先来看看封装后的用法:
                  RetrofitManager.getInstance().getRequestService().getWeather("北京")
                                .compose(RxSchedulers.io_main())
                                .subscribeWith(new DisposableObserver<Object>() {
                                    @Override
                                    public void onNext(Object result) {                                
                                        Log.e("TAG", "result=" + result.toString());
                                    }
    
                                    @Override
                                    public void onError(Throwable e) {
                                        Log.e("TAG", "onError=" + e.getMessage());
                                    }
    
                                    @Override
                                    public void onComplete() {
                                        Log.e("TAG", "onComplete");
                                    }
                                });
    

    封装后的用法大家看到了,链式调用,一步到位,非常简洁明了。接下来我就带着大家一步步封装一个RetrofitManager。

    《二》封装Retrofit+Rxjava的管理类RetrofitManager

    (1)在app的build.gradle下配置Retrofit和Rxjava相关的依赖包

        //rxandroid
        implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
        //rxjava
        implementation 'io.reactivex.rxjava2:rxjava:2.1.10'
        //retrofit
        implementation "com.squareup.retrofit2:retrofit:2.4.0"
        //gsonConverter
        implementation "com.squareup.retrofit2:converter-gson:2.4.0"
        //rxjavaAdapter
        implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
        //retrofit log打印
        implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
    

    (小提醒: Android Studio3.0之后的依赖,由compile变成了implementation。)
    (2)①新建RetrofitManager类,提供单例

    public class RetrofitManager {
        /**
         * 获取单例
         */
        private static RetrofitManager mInstance;
           public static RetrofitManager getInstance() {
            if (mInstance == null) {
                synchronized (RetrofitManager.class) {
                    if (mInstance == null) {
                        mInstance = new RetrofitManager();
                    }
                }
            }
            return mInstance;
        }
    }
    

    ②配置OkHttp,构建Retrofit对象

      private static final long DEFAULT_TIMEOUT = 60L;
      public Retrofit getRetrofit() {
            if (retrofit == null) {
                synchronized (RetrofitManager.class) {
                    if (retrofit == null) {
                        OkHttpClient mClient = new OkHttpClient.Builder()
                                //添加公共查询参数
                                //.addInterceptor(new CommonQueryParamsInterceptor())
                                //.addInterceptor(new MutiBaseUrlInterceptor())
                                //添加header
                                .addInterceptor(new HeaderInterceptor())
                                .addInterceptor(new LoggingInterceptor())//添加请求拦截(可以在此处打印请求信息和响应信息)
                                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                                .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                              //添加https证书,如果有srca.cer的证书,则可以通过sslSocketFactory()配置
                              //.sslSocketFactory(getSSLSocketFactory(context, "srca.cer"))
                                .build();
                        retrofit = new Retrofit.Builder()
                                .baseUrl(BASE_URL)//基础URL 建议以 / 结尾
                                .addConverterFactory(GsonConverterFactory.create())//设置 Json 转换器
                                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//RxJava 适配器
                                .client(mClient)
                                .build();
                    }
                }
            }
            return retrofit;
        }
    
     /**
         * 实现https请求
         */
        private static SSLSocketFactory getSSLSocketFactory(Context context, String name) {
    
    
            if (context == null) {
                throw new NullPointerException("context == null");
            }
    
            //CertificateFactory用来证书生成
            CertificateFactory certificateFactory;
            InputStream inputStream = null;
            Certificate certificate;
    
            try {
                inputStream = context.getResources().getAssets().open(name);
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
    
                certificateFactory = CertificateFactory.getInstance("X.509");
                certificate = certificateFactory.generateCertificate(inputStream);
    
                //Create a KeyStore containing our trusted CAs
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(null, null);
                keyStore.setCertificateEntry(name, certificate);
    
                //Create a TrustManager that trusts the CAs in our keyStore
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init(keyStore);
    
                //Create an SSLContext that uses our TrustManager
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
                return sslContext.getSocketFactory();
    
            } catch (Exception e) {
    
            }
            return null;
        }
    

    ③通过代理的方式,创建ApiServe接口的实例。

      public ApiService getRequestService() {
            return getRetrofit().create(ApiService.class);
        }
    

    ApiService是一个自己定义的interface,所有的网络请求接口的配置,都在此接口内完成。网络请求URL的配置可以参考Retrofit请求参数的配置

    interface ApiService {
        //获取北京的天气信息
    //    "https://www.sojson.com/open/api/weather/json.shtml?city=" + "北京"
        @GET("weather/json.shtml")
        Observable<Object> getWeather(@Query("city")String city);
        //上传文件
       @POST("upload/")
        Observable<UserAvatarBean> uploadFile(@Body RequestBody body);
    }
    

    ④Header的配置

        /**
         * 添加请求头需要携带的参数
         */
        public class HeaderInterceptor implements Interceptor {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Request requestBuilder = request.newBuilder()
                        .addHeader("Connection", HEADER_CONNECTION)
                        .addHeader("token", "token-value")
                        .method(request.method(), request.body())
                        .build();
                return chain.proceed(requestBuilder);
            }
        }
    

    ⑤Retrofit的log日志打印

     /**
         * log打印:参考:http://blog.csdn.net/csdn_lqr/article/details/61420753
         */
        public class LoggingInterceptor implements Interceptor {
            @Override
            public Response intercept(Chain chain) throws IOException {
                //这个chain里面包含了request和response,所以你要什么都可以从这里拿
                Request request = chain.request();
                long t1 = System.nanoTime();//请求发起的时间
                String method = request.method();
                JSONObject jsonObject = new JSONObject();
                if ("POST".equals(method) || "PUT".equals(method)) {
                    if (request.body() instanceof FormBody) {
                        FormBody body = (FormBody) request.body();
                        if (body != null) {
                            for (int i = 0; i < body.size(); i++) {
                                try {
                                    jsonObject.put(body.name(i), body.encodedValue(i));
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        Log.e("request", String.format("发送请求 %s on %s  %nRequestParams:%s%nMethod:%s",
                                request.url(), chain.connection(), jsonObject.toString(), request.method()));
                    } else {
                        Buffer buffer = new Buffer();
                        RequestBody requestBody = request.body();
                        if (requestBody != null) {
                            request.body().writeTo(buffer);
                            String body = buffer.readUtf8();
                            Log.e("request", String.format("发送请求 %s on %s  %nRequestParams:%s%nMethod:%s",
                                    request.url(), chain.connection(), body, request.method()));
                        }
                    }
                } else {
                    Log.e("request", String.format("发送请求 %s on %s%nMethod:%s",
                            request.url(), chain.connection(), request.method()));
                }
                Response response = chain.proceed(request);
                long t2 = System.nanoTime();//收到响应的时间
                ResponseBody responseBody = response.peekBody(1024 * 1024);
                Log.e("request",
                        String.format("Retrofit接收响应: %s %n返回json:【%s】 %n耗时:%.1fms",
                                response.request().url(),
                                responseBody.string(),
                                (t2 - t1) / 1e6d
                        ));
                return response;
            }
    
        }
    
    看一下日志打印的效果,有了日志打印,我们就能轻松的调试每个网络请求了。 image.png
    《三》OkHttp的拦截器Interceptor

    无论是上面添加header,还是处理log日志打印,或是设置缓存,配置一些公共请求参数等等,都是通过添加拦截器addInterceptor()来实现的,所以拦截器有多重要,就不用我多说了啦~

    先举个简单的栗子,了解一下拦截器是个什么东西?
    官方介绍:拦截器是一种能够监控,重写,重试调用的强大机制。拦截发出的请求和传入的响应的日志.
    打个比方:镖局押着一箱元宝走过一个山间小路,突然从山上下来一群山贼拦住了镖局的去路,将镖局身上值钱的东西搜刮干净后将其放行。其中山贼相当于拦截器,镖局相当于一个正在执行任务的网络请求,请求中的参数就是镖局携带的元宝。拦截器可以将网络请求携带的参数进行修改验证,然后放行。这里面其实设计了AOP编程的思想(面向切面编程)。

    详细了解可参考:
    OkHttp拦截器
    Interceptors 拦截器
    手把手带你深入剖析 Retrofit 2.0 源码

    附上RetrofitManager的完整代码(包括Retrofit文件的上传):

    package com.zongxueguan.naochanle_android.net.retrofit;
    
    import com.zongxueguan.naochanle_android.global.API;
    import com.zongxueguan.naochanle_android.retrofitrx.ApiService;
    import com.zongxueguan.naochanle_android.util.UserConstants;
    import com.zxg.framework.library.common.log.Elog;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    import okhttp3.CacheControl;
    import okhttp3.FormBody;
    import okhttp3.HttpUrl;
    import okhttp3.Interceptor;
    import okhttp3.MediaType;
    import okhttp3.MultipartBody;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    import okhttp3.ResponseBody;
    import okhttp3.logging.HttpLoggingInterceptor;
    import okio.Buffer;
    import retrofit2.Retrofit;
    import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
    import retrofit2.converter.gson.GsonConverterFactory;
    
    /**
     * Created by JoJo on 2018/4/24.
     * wechat:18510829974
     * description:
     */
    public class RetrofitManager {
        /**
         * 请求接口实例对象
         */
        private static RetrofitManager mInstance;
        private static final long DEFAULT_TIMEOUT = 60L;
        private Retrofit retrofit = null;
        //请求头信息
        private final String HEADER_CONNECTION = "keep-alive";
    
        public static RetrofitManager getInstance() {
            if (mInstance == null) {
                synchronized (RetrofitManager.class) {
                    if (mInstance == null) {
                        mInstance = new RetrofitManager();
                    }
                }
            }
            return mInstance;
        }
    
        public Retrofit getRetrofit() {
            if (retrofit == null) {
                synchronized (RetrofitManager.class) {
                    if (retrofit == null) {
                        OkHttpClient mClient = new OkHttpClient.Builder()
                                //添加公告查询参数
    //                          .addInterceptor(new CommonQueryParamsInterceptor())
    //                          .addInterceptor(new MutiBaseUrlInterceptor())
                                .addInterceptor(new HeaderInterceptor())
                                .addInterceptor(new LoggingInterceptor())//添加请求拦截(可以在此处打印请求信息和响应信息)
                                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                                .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                                .build();
                        retrofit = new Retrofit.Builder()
                                .baseUrl(API.getInstance().BASE_API_URL)//基础URL 建议以 / 结尾
                                .addConverterFactory(GsonConverterFactory.create())//设置 Json 转换器
                                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//RxJava 适配器
                                .client(mClient)
                                .build();
                    }
                }
            }
            return retrofit;
        }
    
        public ApiService getRequestService() {
            return getRetrofit().create(ApiService.class);
        }
    
        /**
         * 设置公共查询参数
         */
        public class CommonQueryParamsInterceptor implements Interceptor {
    
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                HttpUrl url = request.url().newBuilder()
                        .addQueryParameter("paramsA", "a")
                        .addQueryParameter("paramsB", "b")
                        .build();
                return chain.proceed(request.newBuilder().url(url).build());
            }
        }
    
       /**
         * 添加请求头需要携带的参数
         */
        public class HeaderInterceptor implements Interceptor {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Request requestBuilder = request.newBuilder()
                        .addHeader("Connection", HEADER_CONNECTION)
                        .addHeader("token", "token-value")
                        .method(request.method(), request.body())
                        .build();
                return chain.proceed(requestBuilder);
            }
        }
    
        /**
         * 设置缓存
         */
        public class CacheInterceptor implements Interceptor {
    
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                request.newBuilder().cacheControl(CacheControl.FORCE_CACHE)
                        .build();
                Response response = chain.proceed(request);
                int maxAge = 0;
                // 有网络时 设置缓存超时时间0个小时 ,意思就是不读取缓存数据,只对get有用,post没有缓冲
                response.newBuilder()
                        .header("Cache-Control", "public, max-age=" + maxAge)
                        .removeHeader("Retrofit")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
                        .build();
                // 无网络时,设置超时为4周  只对get有用,post没有缓冲
                int maxStale = 60 * 60 * 24 * 28;
                response.newBuilder()
                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                        .removeHeader("nyn")
                        .build();
                return response;
            }
        }
    
        /**
         * log打印:http://blog.csdn.net/csdn_lqr/article/details/61420753
         */
        public class LoggingInterceptor implements Interceptor {
            @Override
            public Response intercept(Chain chain) throws IOException {
                //这个chain里面包含了request和response,所以你要什么都可以从这里拿
                Request request = chain.request();
                long t1 = System.nanoTime();//请求发起的时间
                String method = request.method();
                JSONObject jsonObject = new JSONObject();
                if ("POST".equals(method) || "PUT".equals(method)) {
                    if (request.body() instanceof FormBody) {
                        FormBody body = (FormBody) request.body();
                        if (body != null) {
                            for (int i = 0; i < body.size(); i++) {
                                try {
                                    jsonObject.put(body.name(i), body.encodedValue(i));
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        Elog.e("request", String.format("发送请求 %s on %s  %nRequestParams:%s%nMethod:%s",
                                request.url(), chain.connection(), jsonObject.toString(), request.method()));
                    } else {
                        Buffer buffer = new Buffer();
                        RequestBody requestBody = request.body();
                        if (requestBody != null) {
                            request.body().writeTo(buffer);
                            String body = buffer.readUtf8();
                            Elog.e("request", String.format("发送请求 %s on %s  %nRequestParams:%s%nMethod:%s",
                                    request.url(), chain.connection(), body, request.method()));
                        }
                    }
                } else {
                    Elog.e("request", String.format("发送请求 %s on %s%nMethod:%s",
                            request.url(), chain.connection(), request.method()));
                }
                Response response = chain.proceed(request);
                long t2 = System.nanoTime();//收到响应的时间
                ResponseBody responseBody = response.peekBody(1024 * 1024);
                Elog.e("request",
                        String.format("Retrofit接收响应: %s %n返回json:【%s】 %n耗时:%.1fms",
                                response.request().url(),
                                responseBody.string(),
                                (t2 - t1) / 1e6d
                        ));
                return response;
            }
    
        }
    
        /**
         * 打印log日志:该拦截器用于记录应用中的网络请求的信息
         */
        private HttpLoggingInterceptor getHttpLogingInterceptor() {
            HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
                @Override
                public void log(String message) {
                    //包含所有的请求信息
                    //如果收到响应是json才打印
                    if ("{".equals(message) || "[".equals(message)) {
                        Log.d("TAG", "收到响应: " + message);
                    }
                    Log.d("TAG", "message=" + message);
                }
            });
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            return httpLoggingInterceptor;
        }
    
        private String BASE_URL_OTHER = "http://wthrcdn.etouch.cn/";
    
        /**
         * 添加可以处理多个Baseurl的拦截器:http://blog.csdn.net/qq_36707431/article/details/77680252
         * Retrofit(OKHttp)多BaseUrl情况下url实时自动替换完美解决方法:https://www.2cto.com/kf/201708/663977.html
    
    //     http://wthrcdn.etouch.cn/weather_mini?city=北京
    //    @Headers({"url_name:other"})
    //    @GET("weather_mini")
    //    Observable<WeatherEntity> getMessage(@Query("city") String city);
         */
        private class MutiBaseUrlInterceptor implements Interceptor {
    
            @Override
            public Response intercept(Chain chain) throws IOException {
                //获取request
                Request request = chain.request();
                //从request中获取原有的HttpUrl实例oldHttpUrl
                HttpUrl oldHttpUrl = request.url();
                //获取request的创建者builder
                Request.Builder builder = request.newBuilder();
                //从request中获取headers,通过给定的键url_name
                List<String> headerValues = request.headers("url_name");
                if (headerValues != null && headerValues.size() > 0) {
                    //如果有这个header,先将配置的header删除,因此header仅用作app和okhttp之间使用
                    builder.removeHeader("url_name");
                    //匹配获得新的BaseUrl
                    String headerValue = headerValues.get(0);
                    HttpUrl newBaseUrl = null;
                    if ("other".equals(headerValue)) {
                        newBaseUrl = HttpUrl.parse(BASE_URL_OTHER);
    //                } else if ("other".equals(headerValue)) {
    //                    newBaseUrl = HttpUrl.parse(BASE_URL_PAY);
                    } else {
                        newBaseUrl = oldHttpUrl;
                    }
                    //在oldHttpUrl的基础上重建新的HttpUrl,修改需要修改的url部分
                    HttpUrl newFullUrl = oldHttpUrl
                            .newBuilder()
                            .scheme("http")//更换网络协议,根据实际情况更换成https或者http
                            .host(newBaseUrl.host())//更换主机名
                            .port(newBaseUrl.port())//更换端口
                            .removePathSegment(0)//移除第一个参数v1
                            .build();
                    //重建这个request,通过builder.url(newFullUrl).build();
                    // 然后返回一个response至此结束修改
                    Elog.e("Url", "intercept: " + newFullUrl.toString());
                    return chain.proceed(builder.url(newFullUrl).build());
                }
                return chain.proceed(request);
            }
        }
    
        /**
         * Retrofit上传文件
         *
         * @param mImagePath
         * @return
         */
        public RequestBody getUploadFileRequestBody(String mImagePath) {
            File file = new File(mImagePath);
            //构建body
            RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
                    .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file))
                    .build();
            return requestBody;
        }
    }
    
    

    相关文章

      网友评论

      • kuen_zhang:一个好的联网框架确实能省很多事,学习了,虽然用的也是retrofit+rxjava,赞一个
      • 78983551cc90:Retrofit这个框架用起来不咋地
        你看你这实现这么简单的功能写了多少行代码
        一只懂音乐的码虫:@依旧冰河 :blush:多谢支持,互相学习成长
        依旧冰河:写的很好啊,喷子别BB,show your code @设计师吴彦祖
        一只懂音乐的码虫:@设计师吴彦祖 期待你写出更好的框架供广大开发者使用!

      本文标题:优雅封装Retrofit+RxJava联网的统一管理类

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