Android网络框架之Retrofit(热豆腐)应用分析

一、引言

2013年Google发布Volley网络库,使用较为简单,请求可以取消,可以提供优先级请求。本人从2014年开始,涉及网络请求一直使用Volley,然而在2016年底,发现不少请求因网络异常而导致堵塞,通过对比压测试,发现使用Retrofit比Volley稳定,用了一段时间感觉还不错,之后就替换成Retrofit。

随着Google对HttpClient的摒弃,和Volley的逐渐没落,OkHttp开始异军突起,而Retrofit则对OkHttp进行了强制依赖。Retrofit也是Square公司开发的一款针对Android网络请求的框架,其实就是对OkHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口。Retrofit非常适合于RESTful url格式的请求,更多使用注解的方式提供功能。

目前,在Android网络请求库中,Retrofit是当下最热的一个网络请求库。

二、Retrofit介绍

Retrofit是一个不错的网络请求库,用官方自己的介绍就是:

Type-safe HTTP client for Android and Java

Retrofit是一个基于 OkHttp 的 RESTful API 请求工具,在使用时其实就充当了一个适配器(Adapter)的角色,主要是将一个 Java 接口翻译成一个 HTTP 请求对象,然后用 OkHttp 去发送这个请求。REST(REpresentational State Transfer)是一组架构约束条件和原则。RESTful架构都满足以下规则:

  • 每一个URI代表一种资源
  • 客户端和服务器之间,传递这种资源的某种表现层
  • 客户端通过四个HTTP动词(GET,POST,PUT,DELETE),对服务器端资源进行操作,实现”表现层状态转化”

核心思想:动态代理。通俗来讲,就是你要执行某个操作的前后需要增加一些操作,比如查看用户个人信息前需要判断用户是否登录,用户访问数据库后想清除用户的访问记录等操作。

GitHub: Retrofit

retrofit注解

  • 方法注解,包含@GET、@POST、@PUT、@DELETE、@PATH、@HEAD、@OPTIONS、@HTTP
  • 标记注解,包含@FormUrlEncoded、@Multipart、@Streaming
  • 参数注解,包含@Query、@QueryMap、@Body、@Field,@FieldMap、@Part,@PartMap
  • 其他注解,包含@Path、@Header、@Headers、@Url

在Retrofit 2.0中,最大的改动莫过于减小库的体积:

  • 去掉了对所有的HTTP客户端的兼容,而钟情于OkHttpClient一个,极大地减少了各种适配代码
  • 拆库,比如将对RxJava的支持设置为可选(需要额外引入库)
  • 将各个序列化反序列化转换器支持设置为可选(需要额外引入库)

Retrofit 2.0升级内容

三、Retrofit应用

3.1 引入依赖

compile('com.squareup.retrofit2:retrofit:2.3.0', {
    exclude module: "okhttp"
})

//gson解析
compile('com.squareup.retrofit2:converter-gson:2.3.0', {
    exclude module: "okhttp"
})

implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'

3.2 配置Retrofit

    public static void initRetrofit() {
        OkHttpClient.Builder builder = new OkHttpClient()
                .newBuilder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS);
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(interceptor);
        retrofit = new Retrofit.Builder()
                .baseUrl(HttpUrls.HOST_URL_BASE)
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    public static <T> T createService(Class<T> service) {
        if (retrofit != null) {
            return retrofit.create(service);
        } else {
            return new Retrofit.Builder()
                    .baseUrl(HttpUrls.HOST_URL_BASE)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(service);
        }
    }

3.3 创建 用于描述网络请求 的接口

Retrofit使用注解来定义一个请求,在方法上面指定请求的方法等信息,在参数中指定参数等信息。

public interface RequestServices {
    @FormUrlEncoded
    @POST(HttpUrls.LOGIN)
    Call<ResponseBody> postLogin(@Field("mobile") String mobile,
                                 @Field("password") String password);


    @GET(HttpUrls.SINA_GET_INFO)
    Call<ResponseBody> getSinaInfo(@QueryMap Map<String, String> map);

    @GET(HttpUrls.WECHAT_GET_ACCESS_TOKEN)
    Call<ResponseBody> getWechatAccessToken(@QueryMap Map<String, String> map);

    @GET(HttpUrls.WECHAT_GET_INFO)
    Call<ResponseBody> getWechatInfo(@QueryMap Map<String, String> map);

    @FormUrlEncoded
    @POST(HttpUrls.REGISTER_USER)
    Call<ServerRequestResult> postRegister(@Field("mobile") String mobile,
                                           @Field("password") String password,
                                           @Field("checkCode") String checkCode);


    @FormUrlEncoded
    @POST(HttpUrls.PASSWORD_VERIFY)
    Call<ServerRequestResult> postVerify(@Field("mobile") String mobile,
                                         @Field("checkCode") String checkCode);


}

3.4 创建 Retrofit 实例

发送请求,我们可以发送同步请求(阻塞当前线程)和异步请求,并在回调中处理请求结果。

POST使用:

        RequestServices service = HttpReqManager.createService(RequestServices.class);
        Call<ResponseBody> serverRequestResultCall = service.postLogin(mMobile, MD5Utils.encode(mPassword));
        serverRequestResultCall.enqueue(getLoginCallback());
    @NonNull
    private StringCallback getLoginCallback() {
        return new StringCallback() {
            @Override
            public void onSuccess(int code, Response<ResponseBody> response) {
                //TODO
            }

            @Override
            public void onFail(int code, String message) {
                //TODO
            }
        };
    }

GET使用:

        RequestServices requestServices = retrofit.create(RequestServices.class);
        Map<String, String> map = new HashMap<>();
        map.put("access_token", oauth2AccessToken.getToken());
        map.put("uid", oauth2AccessToken.getUid());
        Call<ResponseBody> call = requestServices.getSinaInfo(map);
        call.enqueue(new Callback<ResponseBody>() {

            @Override
            public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
                Gson gson = new Gson();
                Message msg = new Message();
                Bundle bundle = new Bundle();
                msg.what = Constants.MSG_SINA_INFO_FAIL;
                SinaInfo sinaInfo;
                try {
                    if (response.body() != null) {
                        String res = response.body().string();
                         //TODO
                    } 
                } catch (Exception e) {
                    //TODO
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                logShow("getInfo>>>onFailure: " + t.toString());
                //TODO
            }
        });
    }

四、总结

Retrofit得益于OkHttpClient的优势,简化 HTTP 请求的库,较之于Volley是一种更加先进的网络框架,已经运行多年,坑差不多都填了,赶紧用上吧!