美文网首页
Retrofit的使用解析

Retrofit的使用解析

作者: dlihasa | 来源:发表于2019-01-17 02:09 被阅读48次
    为什么要用Retrofit

    Retrofit采用了很多的设计模式,使其拥有很好的扩展性,可以和RxJava、Gson、OkHttp这些主流的库进行无缝对接,非常方便。

    初识Retrofit

    Retrofit是一个网络请求框架的封装,应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数,之后由OkHttp完成后续的请求操作,在服务端返回数据之后,OKHttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。

    用一张图来表示:


    Retrofit的简单使用

    (1)在build.gradle中添加Retrofit库依赖

    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    

    在Manifest中添加网络权限

    <uses-permission android:name="android.permission.INTERNET"/>
    

    (2)创建一个用于接收服务器返回数据的实体

    public class MyResponse {
        String name;
        int age;
        String address;
    }
    

    (3)创建一个用于描述网络请求的接口

    public interface MyInterface {
        
        @GET(".../...")
        Call<List<MyResponse>> getCall();
        
    }
    

    Retrofit将 Http请求抽象成Java接口:采用注解描述和配置网络请求参数。
    【1】用动态代理动态将该接口的注解“翻译”成一个http请求,最后再执行 http请求
    【2】注:接口中的每个方法的参数都需要使用注解标注,否则会报错

    (4)创建Retrofit实例

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http:/xx/xx/xx/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
    
    • a. 关于数据解析器(Converter)
      Retrofit支持多种数据解析方式,使用时需要在Gradle添加依赖
    数据解析器 Gradle依赖(版本根据需要修改)
    Gson com.squareup.retrofit2:converter-gson:2.0.2
    Jackson com.squareup.retrofit2:converter-jackson:2.0.2
    Simple XML com.squareup.retrofit2:converter-simplexml:2.0.2
    Protobuf com.squareup.retrofit2:converter-protobuf:2.0.2
    Moshi com.squareup.retrofit2:converter-moshi:2.0.2
    Wire com.squareup.retrofit2:converter-wire:2.0.2
    Scalars com.squareup.retrofit2:converter-scalars:2.0.2
    • b. 关于网络请求适配器(CallAdapter)
      Retrofit支持多种网络请求适配器方式:guava、Java8和rxjava
      使用时如使用的是 Android 默认的 CallAdapter,则不需要添加网络请求适配器的依赖,否则则需要按照需求进行添加 Retrofit 提供的 CallAdapter

    虽然此处栗子中添加了网络请求适配器,但是下文举例中仍然使用的是Android默认的CallAdapter

    使用时需要在Gradle添加依赖:

    网络请求适配器 Gradle依赖
    guava com.squareup.retrofit2:adapter-guava:2.0.2
    Java8 com.squareup.retrofit2:adapter-java8:2.0.2
    rxjava com.squareup.retrofit2:adapter-rxjava:2.0.2

    (5)创建网络请求接口实例

    MyInterface myInterface = retrofit.create(MyInterface.class);//传入字节码创建接口实例
    Call<List<MyResponse>> call = myInterface.getCall();//发送请求的封装(基于OkHttp中的Call)
    

    (6)发送网络请求(同步&&异步)

    /**
    * 发送网络请求(异步)
    */
    call.enqueue(new Callback<List<MyResponse>>() {
         @Override
         public void onResponse(Call<List<MyResponse>> call, Response<List<MyResponse>> response) {
    
          }
    
         @Override
         public void onFailure(Call<List<MyResponse>> call, Throwable t) {
    
          }
    });
    /**
    * 发送网络请求(同步)
    */
    try {
       Response<List<MyResponse>> response = call.execute();
    } catch (IOException e) {
       e.printStackTrace();
    }
    

    (7)处理返回数据,此处的callback已经切换到UI线程

    call.enqueue(new Callback<List<MyResponse>>() {
         @Override
         public void onResponse(Call<List<MyResponse>> call, Response<List<MyResponse>> response) {
                //请求处理,输出结果
                System.out.println(response.body());
          }
    
         @Override
         public void onFailure(Call<List<MyResponse>> call, Throwable t) {
              //请求处理,输出结果
              System.out.println("失败");
          }
    });
    /**
    * 发送网络请求(同步)
    */
    try {
       Response<List<MyResponse>> response = call.execute();
       //请求处理,输出结果
       System.out.println(response.body());
    } catch (IOException e) {
       e.printStackTrace();
    }
    
    Retrofit中非常重要的注解

    Retrofit的注解分为三大类,分别是HTTP请求方法注解标记类注解参数类注解
    1)HTTP请求方法注解有8种:GET、POST、PUT、DELETE、HEAD、PATCH、OPTIONS和HTTP,前7种分别对应HTTP的请求方法,HTTP则可以替换以上7种,也可以扩展请求方法
    2)标记类注解有3种:FormUrlEncoded、Multipart、Streaming。其中,Streaming代表响应的数据以流的形式返回,如果不使用它,则默认会把全部数据加载到内存,所以下载大文件时需要加上这个注解。
    3)参数类注解有10多种:Header、Headers、HeaderMap、Body、Path、Field、FieldMap、Part、PartMap、Query和QueryMap等

    • 常用HTTP请求方法注解 —— GET,及参数类注解
      (1)动态配置URL地址:@Path
    public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);
    }
    

    在GET注解中包含了{user},它对应@Path注解中的“user”,而用来替换{user}的则正是需要传入的“String user”的值。

    (2)动态指定查询条件:@Query,参数拼在url后面

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

    (3)动态指定查询条件组:@QueryMap,参数拼在url后面

    public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
    }
    

    在网络请求中一般我们需要传入很多查询参数,用@Query会比较麻烦(你想想要传很多参数,写很多个@Query),这时我们可以采用@QueryMap,将所有的参数集成在一个Map中统一传递。

    • 常用HTTP请求方法注解 —— POST,及标记类和参数类注解
      (1)传输数据类型为键值对:@Field,参数放在请求体中
    public interface GitHubService {
      @FormUrlEncoded
      @POST("user/edit")
      Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
    }
    

    FormUrlEncoded这一标记类注解来标明这是一个表单请求,然后在方法参数中使用@Field注解来表示所对应的String类参数的键,从而组成一组键值对进行传递

    (2)传输数据类型JSON字符串:@Body

    public interface GitHubService {
     @POST("users/new")
     Call<User> createUser(@Body User user);
    }
    

    用@Body这个注解标识参数对象,Retrofit会将User对象转换为字符串

    (3)单个文件上传:@Part

    public interface MyInterface {
    
        @Multipart
        @POST("user/photo")
        Call<User> updateUser(@Part MultipartBody.Part photo, @Part("desc") RequestBody desc, @Part("photoname") RequestBody photoName);
    
    }
    

    Multipart注解表示允许多个@Part,第一个参数为要上传的图片,第二个和第三个用来传递简单的键值对(键为引号内字符串,值为用来生成RequestBody的数据),注意MultipartBody.Part和RequestBody这两种数据类型的注解方式差异

    举例说明一下:

    File file = new File(Environment.getExternalStorageDirectory(),"aaa.png");
    RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"),file);
    MultipartBody.Part photo = MultipartBody.Part.createFormData("photo","aaa.png",photoRequestBody);
    MyInterface myInterface = retrofit.create(MyInterface.class);
    //设置这个part数据的content-type为null,则此部分数据的请求头无content-type类型
    RequestBody desBody = RequestBody.create(null,"photo");
    RequestBody photonameBody = RequestBody.create(null,"aaa");
    Call<User> call = myInterface.updateUser(photo,desBody,photonameBody);
    

    (4)多个文件上传:@PartMap

    @Multipart
        @POST("user/photo")
        Call<User> updateUser(@PartMap Map<String,RequestBody> photos, @Part("desc") RequestBody desc);
    

    多文件上传使用了Map封装了文件,其他与单个文件上传类似

    • 消息报头——Header
      (1)静态添加消息报头(单个或者多个),请求头不会相互覆盖,具有相同名的请求头都会被包含到请求中
    @Headers("Cache-Control: max-age=640000")
    @GET("widget/list")
    Call<List<Widget>> widgetList();
    
    @Headers({
        "Accept: application/vnd.github.v3.full+json",
        "User-Agent: Retrofit-Sample-App"
    })
    @GET("users/{username}")
    Call<User> getUser(@Path("username") String username);
    

    (2)动态添加请求头(单个或者多个)

    @GET("user")
    Call<User> getUser(@Header("Authorization") String authorization)
    
    @GET("user")
    Call<User> getUser(@HeaderMap Map<String, String> headers)
    

    (3)1和2添加我们可以发现都是在单独的接口中进行的,如果我们需要在每个请求中添加相同的请求头呢,这时候需要使用OkHttp的拦截器
    举个例子,定义一个拦截器如下:

    public class CommonHeaderIntercepter implements Interceptor {
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request original = chain.request();
            HashMap<String,String> map = new HashMap<>();
            map.put("hxid", SpUtils.getString(Constant.HX_ID));
            map.put("identity",SpUtils.getString(Constant.IDENTITY));
            Gson gson = new Gson();
            String cookie = gson.toJson(map);
            Request request = original.newBuilder()
                    .header("User-Agent", "qiyuan")
                    .header("Cookie", cookie)
                    .method(original.method(), original.body())
                    .build();
    
            return chain.proceed(request);
        }
    }
    

    使用自定义的拦截器

    OkHttpClient client = new OkHttpClient.Builder()
                    .addInterceptor(new CommonHeaderIntercepter())
                    .build();
    

    client再设置给Retrofit,每个请求统一添加了这里设置的头部信息,当然这里可以添加各种各样的多个拦截器

    关于Retrofit的使用就先说到这里,后续还会有关于retrofit的更深入的介绍
    另外这里有一篇注解比较全面的介绍

    参考:
    retrofit官方
    这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)

    相关文章

      网友评论

          本文标题:Retrofit的使用解析

          本文链接:https://www.haomeiwen.com/subject/nwosdqtx.html