Retrofit2+okHttp3使用总结

作者: 林水吉 | 来源:发表于2017-03-31 17:25 被阅读3604次

    使用前准备


    Build.gradle文件配置

    • dependencies配置
        compile 'com.squareup.retrofit2:retrofit:2.0.0'
        compile 'com.squareup.retrofit2:converter-gson:2.0.0'
        compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
    

    网络框架搭建


    • 服务创建类封装(HTTP)
    public class ServiceGenerator {
        public static final String API_BASE_URL = "";
        public static int READ_TIMEOUT = 60;
        public static int WRIT_TIMEOUT = 60;
        public static int CONNECT_TIMEOUT = 60;
        private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
                .readTimeout(READ_TIMEOUT,TimeUnit.SECONDS)//设置读取超时时间
                .writeTimeout(WRIT_TIMEOUT,TimeUnit.SECONDS)//设置写的超时时间
                .connectTimeout(CONNECT_TIMEOUT,TimeUnit.SECONDS);
    
        private static Retrofit.Builder builder =
                new Retrofit.Builder()
                        .baseUrl(API_BASE_URL)                 .addConverterFactory(GsonConverterFactory.create());
    
        public static <S> S createService(Class<S> serviceClass) {
            return createService(serviceClass, null);
        }
    
        public static <S> S createService(Class<S> serviceClass, final String authToken) {
            if (authToken != null) {
                httpClient.addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Interceptor.Chain chain) throws IOException {
                        Request original = chain.request();
    
                        // Request customization: add request headers
                        Request.Builder requestBuilder = original.newBuilder()
                                .method(original.method(), original.body());
    
                        Request request = requestBuilder.build();
                        return chain.proceed(request);
                    }
                });
            }
    
            OkHttpClient client = httpClient
                    // 日志拦截器
                    .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                    .build();
            Retrofit retrofit = builder.client(client).build();
            return retrofit.create(serviceClass);
        }
    }
    

    使用说明:
    API_BASE_URL 用来配置api主地址
    READ_TIMEOUT 用来配置读取超时时间
    WRIT_TIMEOUT 用来配置写超时时间
    CONNECT_TIMEOUT 用来配置连接超时时间
    addConverterFactory() 用来设置解析器,此处我们设置的是gson的解析
    addInterceptor() 用来设置日志拦截器

    • 服务创建类封装(HTTPS)
     public class HttpsServiceGenerator {
        public static final String API_BASE_URL = "";
        public static int READ_TIMEOUT = 250;
        public static int WRIT_TIMEOUT = 250;
        public static int CONNECT_TIMEOUT = 250;
        private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    
        private static Retrofit.Builder builder =
                new Retrofit.Builder()
                        .baseUrl(API_BASE_URL)                   .addConverterFactory(GsonConverterFactory.create());
    
        public static <S> S createService(Class<S> serviceClass) {
            return createService(serviceClass, null);
        }
    
        public static <S> S createService(Class<S> serviceClass, final String authToken) {
            if (authToken != null) {
                httpClient.addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Interceptor.Chain chain) throws IOException {
                        Request original = chain.request();
    
                        // Request customization: add request headers
                        Request.Builder requestBuilder = original.newBuilder()
                                .method(original.method(), original.body());
    
                        Request request = requestBuilder.build();
                        return chain.proceed(request);
                    }
                });
            }
            Retrofit retrofit = builder.client(getUnsafeOkHttpClient()).build();
            return retrofit.create(serviceClass);
        }
    
        private static OkHttpClient getUnsafeOkHttpClient() {
            try {
                // Create a trust manager that does not validate certificate chains
                final TrustManager[] trustAllCerts = new TrustManager[]{
                        new X509TrustManager() {
                            @Override
                            public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                            }
    
                            @Override
                            public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                            }
    
                            @Override
                            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                                X509Certificate[] x509Certificates = new X509Certificate[0];
                                return x509Certificates;
                            }
                        }
                };
    
                // Install the all-trusting trust manager
                final SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                // Create an ssl socket factory with our all-trusting manager
                final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
                OkHttpClient okHttpClient =
                        new OkHttpClient.Builder()
                                .readTimeout(READ_TIMEOUT,TimeUnit.SECONDS)//设置读取超时时间
                                .writeTimeout(WRIT_TIMEOUT,TimeUnit.SECONDS)//设置写的超时时间
                                .connectTimeout(CONNECT_TIMEOUT,TimeUnit.SECONDS)
                                .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                                .sslSocketFactory(sslSocketFactory)
                                .hostnameVerifier(new HostnameVerifier() {
                                    @Override
                                    public boolean verify(String hostname, SSLSession session) {
                                        return true;
                                    }
                                }).build();
    
                return okHttpClient;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    

    使用说明:
    可以看出https 和http的服务类主要区别在于retrofit对象的构造方法不同。
    主要就是sslSocketFactory()方法。是用来添加sslsocketFactory的,也就是客户端发送的请求都等于手持了这样的证书,这样就可以和服务器交互了。
    SslsocketFactory对象的获取方法如下:

    final SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
    • 请求体和响应体封装
     {
        "page":2,
        "pageSize":10
    }
    

    Json体类似如上所示的可以封装为如下的请求体/响应体,此处可以借用GsonFormat插件,输入json体就可以快速生产请求体/响应体bean类。

    public class GetTradeDetailRequest {
    
    
        /**
         * page : 2
         * pageSize : 10
         */
    
        private int page;
        private int pageSize;
    
        public int getPage() {
            return page;
        }
    
        public void setPage(int page) {
            this.page = page;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public void setPageSize(int pageSize) {
            this.pageSize = pageSize;
        }
    }
    
    • 服务接口封装
    public interface BalanceService {
        @GET("balance")
        Call<GetBalanceResponse> getBalance(@Header("AccessToken") String accessToken);
    
        @POST("balance/detail")
        Call<GetTradeDetailResponse> getDetail(@Header("AccessToken") String accessToken , @Body GetTradeDetailRequest tradeDetailRequest);
    }
     
    

    使用说明:
    此接口用来声明请求类型,call声明的类型是返回体的bean类,@header是请求的头,@body是返回体的类型。

    • 请求model封装
    public class BalanceModel {
        private static BalanceModel balanceModel;
        private BalanceService mBalanceService;
    
        /**
         * Singleton
         */
        public static BalanceModel getInstance(Context context) {
            if (balanceModel == null) {
                balanceModel = new BalanceModel(context);
            }
            return balanceModel;
        }
    
        public BalanceModel(Context context) {
            mBalanceService =  HttpsServiceGenerator.createService(BalanceService.class);
        }
    
        public Call<GetBalanceResponse> getBalanceResponseCall(String accessToken) {
            Call<GetBalanceResponse> balanceResponseCall = mBalanceService.getBalance(accessToken);
            return balanceResponseCall;
        }
    }
    

    使用说明:
    此接口用来声明请求model的,主要用到的是上面的服务接口。 此类主要用来获取网络请求体的。

    • 响应事件回调类封装
    public abstract class Callback<T extends Object> implements retrofit2.Callback<T> {
    
        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            if (response.raw().code() == 200){
                Log.i("internet response","200");
                onSuccess(response);
            }else if (response.raw().code() == 404){
                Log.i("internet response","404");
                onNotFound();
            }
        }
    
        @Override
        public void onFailure(Call<T> call, Throwable t) {
    
        }
    
    
        public abstract void onSuccess(Response<T> response);
    
        public void onNotFound(){
            return;
        }
    }
    

    使用说明:
    通常在发送网络请求的时候只有两种结果,一是请求发送失败,二是服务器接收到了请求并且响应了。
    onFailure()主要用来处理请求发送失败的情况,onResponse()用来处理服务器的响应内容。
    response.raw().code()的值就是我们在网站开发中遇到的标识代码,200代表成功返回消息体,404代表api路径没找到(api路径配置出错是会导致这样的情况,当然也可能是服务器的环境出了问题,导致手机访问不到),500代表的是服务器内部错误(请求中的参数配置有误会导致这样的情况)。

    • 代码中使用:
    private void httpLoginRequest(String phone, String password) {
            mPushToken = mPushAgent.getRegistrationId();
            GetLoginRequest loginRequest = new GetLoginRequest();
            loginRequest.setPhone(phone);
            loginRequest.setPassword(password);
            loginRequest.setPushtoken(mPushToken);
            loginRequest.setCarrier(mCarrier);
            final Call<GetLoginResponse> callLogin = loginModel.getLoginResponseCall(loginRequest);
            callLogin.enqueue(new Callback<GetLoginResponse>() {
                @Override
                public void onFailure(Call<GetLoginResponse> calllist, Throwable t) {
                    ToastUtils.showToast(LoginActivity.this,"网络服务异常");
                    materialDialog.dismiss();
                    callLogin.cancel();
                }
    
                @Override
                public void onSuccess(Response<GetLoginResponse> response) {
                    GetLoginResponse loginResponse = response.body();
                    userBean = loginResponse.getData();
                    if (loginResponse.getErrcode() == 0) {
                        ToastUtils.showToast(LoginActivity.this,"登录成功");
                        ActivityCollector.finishAll();
                        startActivity(new Intent(LoginActivity.this, MapActivity.class));
                        AppConfigUtils.getInstanse(LoginActivity.this).clearAll();
                        AppConfigUtils.getInstanse(LoginActivity.this).setUserBean(userBean);
                        materialDialog.dismiss();
                    } else if (loginResponse.getErrcode() == 203) {
                        ToastUtils.showToast(LoginActivity.this,"用户名或密码错误");
                        materialDialog.dismiss();
                    }else if (loginResponse.getErrcode() == 999){
                        materialDialog.dismiss();
                        ToastUtils.showToast(LoginActivity.this,"服务器异常,请稍后再试");
                    }
                    callLogin.cancel();
                }
    
                @Override
                public void onNotFound() {
                    materialDialog.dismiss();
                    ToastUtils.showToast(LoginActivity.this,"404");
                    super.onNotFound();
                    callLogin.cancel();
                }
            });
        }
    
    private void httpBalanceRequest(String accessToken) {
            BalanceModel balanceModel = BalanceModel.getInstance(getApplicationContext());
            final Call<GetBalanceResponse> balanceResponseCall = balanceModel.getBalanceResponseCall(accessToken);
            balanceResponseCall.enqueue(new Callback<GetBalanceResponse>() {
                @Override
                public void onResponse(Call<GetBalanceResponse> calllist, Response<GetBalanceResponse> response) {
                    GetBalanceResponse balanceResponse = response.body();
                    if (balanceResponse.getErrcode() == 0) {
                        mMoneyTV.setText(balanceResponse.getData().getBalance());
                    } else if (balanceResponse.getErrcode() == 999) {
                        ToastUtils.showToast(BalanceActivity.this,"服务器异常,请稍后再试");
                        mMoneyTV.setText("0.00");
                    } else if (balanceResponse.getErrcode() == 403) {
                        ToastUtils.showToast(BalanceActivity.this,"登录已失效,请重新登录");
                        AppConfigUtils.getInstanse(BalanceActivity.this).clearAll();
                        ActivityCollector.finishAll();
                        LoginActivity.actionStart(BalanceActivity.this,mPhone,"");
                    }
                    balanceResponseCall.cancel();
                }
    
                @Override
                public void onFailure(Call<GetBalanceResponse> calllist, Throwable t) {
                    ToastUtils.showToast(BalanceActivity.this,"网络服务异常");
                    balanceResponseCall.cancel();
                }
            });
        }
    

    使用说明:
    这段代码使用的是自己封装的响应事件回调类,当然也可以用第二张图retrofit默认的那套,用自己封装的有个好处就是404not found 可以处理进行操作,如果用默认的那套,在404的时候这段代码就会崩溃。

    相关文章

      网友评论

        本文标题:Retrofit2+okHttp3使用总结

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