简介

Retrofit2是square公司开源的网络库,该公司的另一个库Okhttp,相信大家应该同样熟悉,在Retrofit流行之前,Okhttp是我们使用比较多的几个网络库之一。Retrofit虽然时下最流行,其实并没有替代Okhttp,Retrofit默认还是基于Okhttp去完成底层网络处理的,只是在上层做了进一步的封装,使开发者更易使用而已。本篇我们就来谈一谈Retrofit2的使用。

示例引入

添加依赖

dependencies {
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
}

Retrofit实例化

最基本的Retrofit创建:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://localhost:6666/")
        .build();

接口定义

使用@GET定义了一个查询接口:

public interface AdsService {

    @GET("ads")
    Call<ResponseBody> getAds();
}

接口调用

调用getAds接口,并设置监听回调:

Call<ResponseBody> call = service.getAds();
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        try {
            System.out.println(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        t.printStackTrace();
    }
});

注解介绍

Retrofit很重要的一个特色就是,使用注解配置网络参数,非常方便和优雅。

注解可以分为三类:

1、HTTP请求方法类

POST、DELETE、PUT、GET、HEAD、PATCH、OPTIONS、HTTP

下面以常用的GET、POST方法,以及比较特殊的HTTP注解为例来说明。

GET

@GET("ads")
    Call<ResponseBody> getAds();

POST

@POST("login")
    @FormUrlEncoded
    Call<ResponseBody> login(@Field("username") String name, @Field("password") String pwd);

HTTP

HTTP可以替换其他7个注解使用:

@HTTP(method = "GET", path = "ads", hasBody = false)
    Call<ResponseBody> getAds();

2、标记类

FormUrlEncoded

表示请求提是一个form表单,和Field、FieldMap配合使用

Multipart

表示请求体是一个支持文件上传的form表单,和Part、PartMap配合使用

Streaming

表示响应体的数据用流的形式返回

3、参数类

用于方法

这里就一个注解:Headers

@GET("ads")
        @Headers({"headerName1: headerValue1", "headerName2: headerValue2"})
        Call<ResponseBody> getAds();
用于方法参数
Path
@HTTP(method = "GET", path = "ads/{id}", hasBody = false)
    Call<ResponseBody> getAd(@Path("id") int id);
Url
@GET
    Call<ResponseBody> getAd(@Url String url, @Query("id") int id);

注:使用了Url注解,请求方法中就无需配置url参数了

Query和QueryMap
@GET("ads")
    Call<ResponseBody> getAd(@Query("id") int id);

    @GET("ads")
    Call<ResponseBody> getAds(@QueryMap Map<String, String> map);
Field和FieldMap
@POST("login")
    @FormUrlEncoded
    Call<ResponseBody> login(@Field("username") String name, @Field("password") String pwd);

    //或者写成这样
    @POST("login")
    @FormUrlEncoded
    Call<ResponseBody> login(@QueryMap Map<String, String> map);
Header
@GET("ads")
    Call<ResponseBody> getAds(@Header("headerName") String headerValue);
Part和PartMap
@POST("upload")
    @Multipart
    Call<ResponseBody> uploadFile1(@Part("name") RequestBody name, @Part MultipartBody.Part file);

    @POST("upload")
    @Multipart
    Call<ResponseBody> uploadFile2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file);

使用Converter

这里只以常用的GsonConverter为例

添加converter-gson库依赖

dependencies {
    compile 'com.squareup.retrofit2:converter-gson:2.0.2' //gson转换器,将JSON数据映射为对象
    compile 'com.google.code.gson:gson:2.2.4' //Gson解析库
}

添加GsonConverterFactory

retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类
                .build();

接口修改

public interface AdsService {

    @GET("ads")
    Call<AdResult> getAds();
}

这里的AdResult对应JSON映射的对象

接口调用

Call<AdResult> call = service.getAds();
        call.enqueue(new Callback<AdResult>() {
            @Override
            public void onResponse(Call<AdResult> call, Response<AdResult> response) {
                if (response != null && response.isSuccessful()) {

                }
            }
            @Override
            public void onFailure(Call<AdResult> call, Throwable t) {

            }
        });

使用CallAdapter

这里只以常用的RxJava2CallAdapter为例

添加RxJava依赖

dependencies {
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' //RxJava2CallAdapter
    compile 'io.reactivex.rxjava2:rxjava:2.1.3'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
}

添加RxJava2CallAdapterFactory

retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();

接口修改

public interface AdsService {

    @GET("ads")
    Flowable<Response<AdResult>> getAds();
}

这里的Response是retrofit2.Response,便于获取Response状态信息。

接口调用

Flowable<Response<AdResult>> flowable = service.getAds();
        flowable.map(new Function<Response<AdResult>, List<Ad>>() {
            @Override
            public List<Ad> apply(Response<AdResult> retrofitResponse) throws Exception {
                if (retrofitResponse != null && retrofitResponse.isSuccessful()) {

                    return list;
                }
                return null;
            }
        }).subscribeOn(SchedulerProvider.getInstance().io())
                .observeOn(SchedulerProvider.getInstance().ui())
                .subscribe(new DefaultSubscriber<List<Ad>>() {
                    @Override
                    public void onNext(List<Ad> ads) {

                    }

                    @Override
                    public void onError(Throwable t) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

添加Interceptor

日志Interceptor

如果使用了gson解析,打印网络请求和响应的日志,就没那么方便了,实际的网络操作都被封装起来了。我们需要使用squareup提供的另一个库来满足打印日志的需求,所以还要添加logging-interceptor库依赖。

添加依赖
dependencies {
    compile 'com.squareup.okhttp3:logging-interceptor:3.6.0' //日志拦截器
}
设置Interceptor
private Api() {

        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .readTimeout(30, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);

        if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new AdsLogger());
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
            builder.addInterceptor(loggingInterceptor);
        }
        ...
    }

    private static class AdsLogger implements HttpLoggingInterceptor.Logger {
        @Override
        public void log(String message) {
            Log.i("RetrofitLog", "" + message);
        }
    }

这里,我们可以通过BuildConfig.DEBUG控制是否支持日志打印。

总结

以上大概就是本人目前学习Retrofit2的一点心得,谈不上深入,也没有具体到项目,只能算是入门教程,存在错误的地方,希望指正。

参考资料

你真的会用Retrofit2吗?Retrofit2完全教程
Retrofit打印请求地址和返回内容
Retrofit — Getting Started and Creating an Android Client