Retrofit 的使用简介

Retrofit 的使用介绍

AndroidJava安全的http请求客户端

版本

去年年底更新到V2.0.0了。V1&&V2

优势

在V1.X.X 的时候:

  • 可以利用接口,方法和注解参数(parameter annotations)来声明式定义一个请求应该如何被创建

    @POST("/classes/info")
    void insertInfoDb(@Body ContactBean bean, Callback<ContactBean> callback);
    
    @GET("/classes/info")
    void getDbInfos( Callback<ResultBean> callback);
    
  • 可自定义HttpClient

    builder.setClient(new AndroidApacheClient())
        .setClient(new UrlConnectionClient())
        .setClient(new ApacheClient())
        .setClient(new OkClient())
        .setClient(new CustomClient())
    
  • 可自定义序列化机制

    builder.setConverter(new GsonConverter());
    builder.setConverter(new JacksonConverter());
    builder.setConverter(new ProtoConverter());
    builder.setConverter(new WireConverter());
    
    builder.setConverter(new SimpleXMLConverter());
    
    builder.setConverter(new CustomConverter());
    
  • 支持Rxjava

    @GET("/news/latest")
    Observable<DailyStories> getLatestDailyStories();
    
  • 支持同步异步请求

    @GET("/news/latest")
    void getLatestDailyStories(Callback<DailyStories> callback);
    @GET("/news/latest") 
    DailyStories getsLatestDailyStories();
    

注解的相关类型

  • 请求方法

每个方法必须有一个HTTP请求注释提供方法和相对URL。有五个内置注释:GET、POST、PUT、DELETE和头部。资源的相对URL中指定注释。

  • URL操作

    请求URL使用替换块和参数可以动态更新方法。是一个字母数字字符串替换块{和}包围。相应的参数必须与@path注释使用相同的字符串。

    例如:

    @GET("/start-image/{width}*{height}")
    void getStartImage(@Path("width") int width, @Path("height") int height, Callback<StartImage> callback);
    

    查询参数也可以被添加。

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

    如果参数特别多,那么就是用map,咱们不就是这个玩意儿嘛!

    @GET("group/{id}/users")
    Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
    
  • 请求体

    可以指定一个对象作为HTTP请求体@Body注释。
    序列化功能也是可替换的。默认是用的 GSON。

    @POST("/classes/info")
    void insertInfoDb(@Body ContactBean bean, Callback<ContactBean> callback);
    
  • 表单编码

    如果需要发送表单编码,那么就需要是用@FormUrlEncoded。每个键-值对注释@Field包含名称和对象提供的值。

    @FormUrlEncoded
    @POST("user/edit")
    
  • 文件上传?

    @Multipart
    @PUT("user/photo")
    Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
    
  • 头操作

    你可以使用@Headers注释静态头的方法。
    这里需要注意下——头不会互相覆盖。具有相同名称的所有头文件都包括在请求。

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

    如果我们在方法中动态再使用@Header的的话,@Header必须提供相应的参数。如果该值为null,头就会被忽略掉。然后会通过toString()获取它的相关值并使用。

    如果你需要在每一个方法中都要添加相关的header,那么这种方法就比较繁琐了。可以使用OkHttp interceptor,在创建的时候直接添加相关参数

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

以上就是Retrofit提供的相关注解了。

举个例子

  • 定义一个接口:

    public interface BombApiService {
    @POST("/classes/info")
    void insertInfoDb(@Body ContactBean bean, Callback<ContactBean> callback);
    @GET("/classes/info")
    void getDbInfos( Callback<ResultBean> callback);
    @GET("/classes/info")
    Observable<ResultBean> getDbInfos();
    @POST("/batch")
    void insertDbInfos(@Body BatchBean bean,Callback<List<BatchResultBean>> callback);
    }
    
  • 获取这个接口的实例化对象:

     public static BombApiService getBombApiService() {
        return new RestAdapter.Builder()
                .setEndpoint(BOMB_API)//hosturl
                .setConverter(new GsonConverter())
                .setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)//是否打印日志
                .setRequestInterceptor(new RequestInterceptor() {
                    @Override
                    public void intercept(RequestFacade request) {
                        request.addHeader("Content-Type", "application/json");
                        request.addHeader("X-Bmob-Application-Id", APPLICATION_ID);
                        request.addHeader("X-Bmob-REST-API-Key", API_KEY);
                    }
                })//这里就是使用Interceptor来添加相关的header,但是这个是V1里面的相关写法。V2.0请往下看。
                .build()
                .create(BombApiService.class);
    }
    
  • 相关的请求方法:

    getBombApiService().getDbInfos()
    

    酱紫,就已经成功调取相关的api了!!


V1.0的一些不足

如果你想要操作某次请求返回的数据,比如说返回的 Header 部分或者 URL,你又同时想要操作序列化后的数据部分。

同一个方法同步异步的定义必须分开定义两次。

声明式 API 需要传入一个 Date,但是一个 Date 会有多种不同的格式表示。有的接口可能需要一个字符串,有的可能需要一个分隔开的日期表示(尤其是那些比日期要复杂很多的对象,可能会有更多的表示方法。
一中RestAdapter 只能绑定一个 Converter 对象。
url的拼接相对死板:@POST(“/classes/info”),这里必须以/开头

V2.0.0的相关新特性

  • 1、Call方法的使用,引入了Call方法。

    @GET("/some/proto/endpoint")
    Call<SomeProtoResponse> someProtoEndpoint();
    
  • 2、同步异步同一个方法的支持(基于call方法)引入call方法之后,使用完全和OkHttp的Call方法是一致的。

    同步调用:我们可以直接调用它的 execute 方法,但是得留意一下,这个方法只能调用一次。重复调用会抛出异常

    response = call.execute();
    
    // This will throw IllegalStateException:
    response = call.execute();
    

    异步调用:我们可以直接调用它的 enqueue 方法

    call.enqueue(new Callback<List<Contributor>>() {
      @Override void onResponse(/* ... */) {
        // ...
      }
    
      @Override void onFailure(Throwable t) {
        // ...
      }
    });
    

    事实取消相关请求:当你将一些异步请求压入队列后,甚至你在执行同步请求的时候,你可以随时调用 cancel() 方法来取消请求。

    Call<List<Contributor>> call =
    gitHubService.repoContributors("square", "retrofit");
    
    call.enqueue(         );
    // or...
    call.execute();
    
    // later...
    call.cancel();
    Parameterize
    
  • 3、参数化的响应对象&支持对header和序列化数据的同时操作

    在这个新的Response对象增加了曾经一直被我们忽略掉的重要元数据:响应码(the reponse code),响应消息(the response message),以及读取相应头(headers)。
    同时还提供了一个很方便的函数来帮助你判断请求是否成功完成,其实就是检查了下响应码是不是 200。然后就拿到了响应的 body 部分,另外有一个单独的方法获取 error body。基本上就是出现一个返回码,然后调用相对应的函数的。只有当响应成功以后,我们会去做反序列化操作,然后将反序列化的结果放到 body 回调中去。如果出现了返回了网络成功响应(返回码:200)却最终返回 false 的情况,我们实际上是无法判断返回到底是什么的,只能将 ResponseBody(简单封装的了 content-type,length,以及 raw body部分) 类型交给你去处理。

    Call<List<Contributor>> call =
    gitHubService.repoContributors("square", "retrofit");
    Response<List<Contributor>> response = call.execute();
    
    response.isSuccess()//判断是否成功
    response.headers()//成功获取相关的header
    response.errorBody//请求异常的相关封装
    
  • 4、动态 URL Parameter

    Retrofit 2.0 有了新的 标注:@Url ,允许你直接传入一个请求的 URL。

    @GET
    Call<List<Contributor>> repoContributorsPaginate(
    @Url String url);
    
  • 5、OkHttp 提供支持,其他不在支持

    如果需要统一添加header,那么就是直接在这个client里面添加对应的RequestInterceptor.

    okHttpClient.interceptors().add(requestInterceptor);
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .client(client)
    .build();
    
  • 6、Adapter的创建

    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .build();
    
  • 7、不同Converter的同时支持

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .addConverterFactory(ProtoConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();
    

    这里要注意Converter的添加顺序,因为GsonConvertor是所有的都能处理的,所以这个一定要放在最后面。有点儿像java的捕获异常,子异常要放在上面,父异常要放在最下面。

  • 8、相关路径写法的改变
    现在,让我们来看一下 Retrofit 的类型是如何替代 REST adapter 类型的,以及如何初始化。原来的方法叫做 endpoint(), 不过现在我们称之为 baseUrl(), baseUrl 就是你所请求的 Server 的 URL,下面是一个请求 GitHub Api 的例子:

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .build();
    
    interface GitHubService {
      @GET("/repos/{owner}/{repo}/contributors")
      Call<List<Contributor>> repoContributors(
          @Path("owner") String owner,
          @Path("repo") String repo);
    }
    
    GitHubService gitHubService = retrofit.create(GitHubService.class);
    
    其实url是这样的:https://api.github.com/repos/square/retrofit/contributors
    
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/v3/")
    .build();
    
        interface GitHubService {
          @GET("repos/{owner}/{repo}/contributors")
          Call<List<Contributor>> repoContributors(
              @Path("owner") String owner,
              @Path("repo") String repo);
        }
    
    其实url是这样的: https://api.github.com/v3/repos/square/retrofit/contributors
    

    意思就是在V2.0之后,我们不需要刻意的使用/开头的url了,如果这样开头,会被认为 是一个绝对路径。
    所以现在我们的BaseUrl应该是以”/”结束的,然后定义get等方法时直接拼接对应的url,而不用刻意的使用”/”开头!!。

  • 9、Rxjava的相关支持

    CallAdapterFactory 是一个知道如何将 call 实例转换成其他类型的工厂类。目前,我们只有 RxJava 的类型,也就是将 Call 类型转换成 Observable 类型。

    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(ProtoConverterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .build();
    

其中 1 8 9是对应V1版本在初始化的方法上差异比较大的地方吧!!

报错

引入Retrofit2.0之后系统提示GsonConverterFactory或者RxJavaCallAdapterFactory等找不到???
不要惊慌,这些都要分别引入的!!而且注意对应的包名确定一致,bate版本使用bate版本相关的Factory

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

或者

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'

相关资料

Retrofit2.0 来自 Droidcon NYC 2015 一个演讲

Retrofit 官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值