Android中使用Retrofit库进行Http通讯

合适的就是好的

在Anrdoid中,有很多种Http通讯网络库可供我们使用,比如Volley, OKHttp和Retrofit等,没有最好的,只有最适合的。在不同的场景下,我们会有不同的选择。
如果只是单纯地从服务端的restful api接口中获取json格式的数据,相信很多人都会选择Retrofit,因为其实现起来最简单,最方便。
但是如果还需要从服务端获取图片,那相信很多人会说Volley会做得更好啊,因为Retrofit没有现成的接口,而Volley有NetworkImageView或者ImageRequest等,但可能也会有人说,直接用Glide和Picasso会更舒服呀。

如何使用Retrofit

目前都是用Android Studio 来进行开发的,依赖什么的都是通过 gradle来配置,所以按照以下几步走:

Gradle配置

    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'

其中converter-gson,是retrofit2提供的,将Response的Body转化为json对象的方法,也就是说Retrofit2提供了关于Json的转化,我们不需要自己再去做这个处理了。

Proguard配置

在导入任何第三方包的时候,我第一个总会去找其Proguard配置是什么。一般来说,官方提供的文档中会告诉我们如何使用这些库,也会提供一段Proguard配置来让我们在应用中进行配置

#retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions

在这里,其实有一点要注意的,-keepattributes Signature,是为了Gson配置的,是因为Gson在转化Field(字段)的时候会使用到存储在类中泛型信息,而Proguard默认会将这些信息给移除掉,所以我们需要Keep住这些Signature。Signature 是字段,方法和类的签名信息,用来标识其唯一性的。同一个方法,参数不同,如何区分,其实就是靠Signature。

声明接口 TestService

声明我们需要与服务器进行通讯的请求,包括请求类型,请求地址,请求参数,参数的形式等。

public interface TestService {
    @FormUrlEncoded
    @POST("http://ip:port/api/login")
    Call login(@Field("username") String username,
                            @Field("password") String password);
}

注释 @FormUrlEncoded 指明了请求的内容(content)会使用 form-encoded 的形式,而我们想要传递给服务器的参数,则必须用 @Field 来指定,如上述方法,指定了login方法会指向服务器的http://ip:port/api/login 接口,请求类型是 Post,指定参数为 username 和 password,而Call 则是Retrofit 定义的一次发送Request并接收Response的一个接口,可以将其看作是一次请求的触发。

创建Retrofit和TestService对象

 Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(SharedPreferenceHelper.getServerHost())
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(buildClient())
                    .build();
 TestService service = retrofit.create(TestService.class);

通过Retrofit.Builder.build() 方法,我们可以创建Retrofit对象,再通过Retrofit对象,我们创建TestService对象,从而真正地将 TestService 接口实例化。

  • 利用 baseUrl 方法,我们可以指明服务器地址,比如:
.baseUrl("http://192.168.1.100")

则我们指定了服务器地址为 http://192.168.1.100,这样,我们在声明接口TestService的api时,就可以只声明路径,如下:

    @FormUrlEncoded
    @POST("/api/login")
    Call login(@Field("username") String username,
                            @Field("password") String password);
  • 利用 addConverterFactory(GsonConverterFactory.create()) 添加 Gson 转换

这就是我们在 build.gradle中引入的 converter-gson 使用的地方了。

  • 利用 client 方法,我们可以添加一些 Interceptor 来记录请求的参数,整个请求的时间等。
    如下,我们可以声明一个LoggingInterceptor,如下:
public class LoggingInterceptor implements Interceptor{

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();
        long t1 = System.nanoTime();
        Logger.v("request:" + request.toString());
        if (request.body() != null) {
            FormBody body = (FormBody) request.body();
            int size = body.size();
            for (int i = 0; i < size; i++) {
                Logger.v(body.name(i) + " : " + body.value(i));
            }
        }
        Response response = chain.proceed(request);
        long t2 = System.nanoTime();
        Logger.v(String.format("received " + response.toString() + " in %.1fms%n", (t2 - t1) / 1e6d));
        return response;
    }
}

在这里,通过 FormBody(因为我们使用的是 Form-Encoded的方法)来将RequestBody其中的参数和值给打印出来,同样的,我理所当然地以为,也可以将response.body也可以打印出来,发现可以通过response.body.string() 方法,可以将response的内容给打印出来,比如这样

if (response.body() != null) {
   Logger.v("response.body: " + response.body().string());
}

结果,真的打印出来了,如我所愿,然而,踩坑了。


!!,在这里有个坑,不能使用 response.body.string() 方法, 因为 string() 方法会将response的内容给读取了,导致整个请求关闭,这样在后续操作,就会收到Exception: close了。


定义了 LoggingInterceptor,创建OKHttpClient,如下:

    private static OkHttpClient buildClient() {
        OkHttpClient client = new OkHttpClient.Builder()
                .addNetworkInterceptor(new LoggingInterceptor())
                .build();
        return client;
    }

再通过 .client(buildClient)方法,设置给Retrofit,达到在TestService调用方法的时候进行拦截。

调用TestService.login方法创建Call,将调用Call的enqueue方法

    private void doLogin() {
       Call call = testService.login("username","password");            
       call.enqueue(new Callback() {
            @Override
            public void onResponse(Response response) {
                LoginResult loginResult = response.body();
                //do something about loginResult
            }

            @Override
            public void onFailure(Throwable t) {
                //do something about throwable t
            }
        });
    }

通过 call.enqueue方法,将call放进请求队列里,并声明一个Callback,通过callback的onResponse方法和onFailure方法,分别对正常的Response和请求过程中出现的错误进行处理。

对Retrofit2的基本使用,到此就结束了。

参考并感谢
高效率http retrofit okhttp
Retrofit
Interceptors

你可能感兴趣的:(Android,开发记录)