Retrofit2.0使用简介

随着Google抛弃HttpClient以及Volley的逐步没落,OkHttp越来越受到开发者的青睐。在之前的博文中《OkHttp源码解析》,我们已经对OkHttp的使用和原理进行了分析。Retrofit作为square公司的另一网络利器,则是在OkHttp的基础上,对网络请求做了更加系统、简洁的封装,本博文就来带大家认识和学习Retrofit,将知识转化为战斗力。
本博文基于Retrofit 2.3.0进行讲解

Retrofit是什么?

按照惯例,我们首先来看下GitHub上Retrofit的解释。
Type-safe HTTP client for Android and Java by Square, Inc.
翻译下:
Square公司为Android和Java开发的类型安全的Http Client。

Retrofit其实就是对OkHttp的封装,使用面向接口的方式进行网络请求(大大简化了我们的代码,感觉这一点和Spring中Controller的接口编写类似),它使用动态生成的代理类封装了接口,而且使用很多注解提供功能。

如何使用Retrofit?

   //Retrofit本体
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    //OkHttp
    compile 'com.squareup.okhttp3:okhttp:3.9.0'
    //OkHttp依赖的okio
    compile 'com.squareup.okio:okio:1.13.0'
    //Retrofit Gson转换器
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'

忘记告诉你,Retrofit的使用要依赖于OkHttp,所以你还要加入对OkHttp库的依赖(当然别忘了,还要okio)。

当然,如果是Android开发者,不要忘记请求、添加网络权限。


当你做完了如上的动作,我们的武器库就填好了,下面我们就来看看如何使用我们的武器吧。

API

这个章节,我们主要来讨论和学习下如何使用Retrofit。示例都是一些简单的例子,以便我们快速上手Retrofit。

1. 示例

  1. 定义HTTP API接口
public interface GitHubService {
  @GET("users/{user}/repos")
  Call> listRepos(@Path("user") String user);
}

Retrofit会使用动态代理的方式,将我们定义的Java Interface转换为网络请求接口,我们只需要定义和使用,暂时不关注它是如何进行转换的。

  1. 定义Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

从这段代码上看,Retrofit的构造同样使用了设计模式中的[建造者模式],可见该模式的使用之普遍。
在构造Retrofit时我们要注意以下几点:

  • baseUrl以/结尾。
  • @GET等接口URL不要以/开头。
  1. 转换接口
GitHubService service = retrofit.create(GitHubService.class);

Retrofit使用动态代理的方式,实现了我们定义的GitHubService接口。

  1. 调用API接口
GitHubService service = retrofit.create(GitHubService.class);

//同步请求
//https://api.github.com/users/zhangshuaisir/repos
Call> call = service.listRepos("zhangshuaisir");
try {
     Response> repos  = call.execute();
} catch (IOException e) {
     e.printStackTrace();
}

//不管同步还是异步请求,call只能执行一次,否则会抛 IllegalStateException
Call> clone = call.clone();

//异步请求
//Android 回调接口执行在Android主线程中
call.enqueue(new Callback>() {
        @Override
        public void onResponse(Call> call, Response> response) {
            for (Repo repo : response.body()) {
                System.out.println(repo.toString());
            }
        }

        @Override
        public void onFailure(Call> call, Throwable t) {
            t.printStackTrace();
        }
    });
  1. 终止请求
call.cancel();

即使该请求正在执行,调用该接口仍然可以终止它。

2.Annotation

在上面的示例中,我们看到了[ @GET("users/{user}/repos")]注解,凭借我们的直觉注解代表是GET请求,那么本章节就带大家来认识下Retrofit注解相关内容。

注解的作用:
添加在方法上的注解和参数,代表了Retrofit如何处理这个请求。

  1. 方法注解
    每一个方法都必须包含一个提供请求方法和相对URL的注解,Retrofit内置了五个注解,资源的相对URL在注解中指定。内置的注解有:
  • @GET
  • @POST
  • @PUT
  • @DELETE
  • @HEAD
    这些注解对应了我们请求处理方式,相信大家看完就能理解,在此不再赘述。

2 URL

(1)动态URL

  • 请求URL可以使用方法上的替换块和参数动态更新请求URL。
  • 替换块是由{}包围的字母数字字符串,使用@Path注释相应的参数。
@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId);

我们可以将{id}理解为占位符,在实际的运行中,该值会被@Path("id")标注的参数替换,从而达到动态更新URL的目的。

@Path注解的定位是替换URL的路径,而不是查询参数替换。

(2)添加查询参数

我们可以通过使用@Query注解来向URL中添加查询参数,示例如下:

@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @Query("sort") String sort);

在实际的运行中,@Query("sort")注解会被如此解释:https://api.github.com/users/zhangshuaisir/repos?sort=desc.

对于复杂的查询参数构造,可以使用@QueryMap来处理。

@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @QueryMap Map options);

@Query和@QueryMap注解定位于URL中查询参数的替换,与@Path(URL路径替换)的作用和定位不同,使用时要注意。

  1. 请求体
    一个对象可以通过使用@Body注解作为HTTP request body使用。
@POST("users/new")
Call createUser(@Body User user);

实体会根据配置在Retrofit的converter进行转换,如果在构造Retrofit的时候我们没有配置converter,那么只能使用RequestBody类型的实体。

  1. 表单方式传递值
    Retrofit支持传递[form-encoded]数据,使用@FormUrlEncoded注解进行标识。
    每个key-value值,使用@Field进行标识。
    通过@POST指明url,添加FormUrlEncoded,然后通过@Field添加参数即可。
    当我们有很多个表单参数时也可以通过@FieldMap注解和Map对象参数来指定每个表单项的Key,value的值。
@FormUrlEncoded
@POST("user/edit")
Call updateUser(@Field("first_name") String first, @Field("last_name") String last);
  1. 文件上传
    Retrofit同样支持Multipart,使用@Mutipart进行注解,Parts使用@Part注解。
@Multipart
@PUT("user/photo")
Call updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
  1. Header
    可以使用@Headers标签静态来指定请求的Header。
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call> widgetList();


@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call getUser(@Path("username") String username);

当然我们也可以使用@Header标签动态指定Header。

@GET("user")
Call getUser(@Header("Authorization") String authorization)

3. 同步&异步

Call实例可以执行同步和异步请求,但是每个实例只能执行一次,可以使用clone方法创建一个新的示例。

在Android中,callbacks是执行在主线程中的;在JVM中,callbacks在调用请求的线程中执行。

4.Retrofit配置

CONVERTERS

默认情况下,Retrofit只能将HTTP Body实体转换为OkHttp的ResponseBody类型;
而且它也只能接收RequestBody类型的请求实体。

除了默认的转换器,我们还可以添加自定义的转换器,我们常用的主要有以下几种:
Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

  • 示例
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

GitHubService service = retrofit.create(GitHubService.class);

如果以上的转换器仍然满足不了你的需求,那么我们可以自定义转换器。
只需要继承Converter.Factory类,我们就可以自定义转换器。
Converter.Factory类是一个抽象类,我们来看下它的定义。

  /** Creates {@link Converter} instances based on a type and target usage. */
  abstract class Factory {
    /**
     * Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for
     * response types such as {@code SimpleResponse} from a {@code Call}
     * declaration.
     */
    public @Nullable Converter responseBodyConverter(Type type,
        Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

    /**
     * Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
     * values.
     */
    public @Nullable Converter requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      return null;
    }

    /**
     * Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Field @Field}, {@link FieldMap @FieldMap} values,
     * {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
     * {@link Query @Query}, and {@link QueryMap @QueryMap} values.
     */
    public @Nullable Converter stringConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }

    /**
     * Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
     * example, index 1 of {@code Map} returns {@code Runnable}.
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    /**
     * Extract the raw class type from {@code type}. For example, the type representing
     * {@code List} returns {@code List.class}.
     */
    protected static Class getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }

关于自定义Converter,有以下几点我们需要注意:

  • responseBodyConverter:主要完成ResponseBody到实际的返回类型的转化,这个类型对应Call<\XXX>里面的泛型XXX。
  • requestBodyConverter:完成对象到RequestBody的构造。主要是对应@Body注解,其实@Part等注解也会需要requestBodyConverter,只不过我们的参数类型都是RequestBody,由默认的converter处理了。
  • 一定要注意,检查type如果不是自己能处理的类型,记得return null (因为可以添加多个,你不能处理return null ,还会去遍历后面的converter).

Proguard

# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions

-dontwarn okio.**

你可能感兴趣的:(Retrofit2.0使用简介)