Retrofit教程

正文

Retrofit简介
        Rrotrofit是一个RESTful架构的HTTP网络请求框架的封装。网络请求工作,本质上是 Okhttp 完成的,Retrofit 仅负责网络请求接口的封装。Retrofit接口层封装了requestParams、Header、Url 等信息,后续的请求工作由OkHttp来完成。服务端返回数据后,OkHttp将返回结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。
public interface GetRequest_Interface {
    @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json")
    Call<Translation>  getCall();
    // @GET注解的作用:采用Get方法发送网络请求
    // getCall() = 接收网络请求数据的方法
    // 其中返回类型为Call<*>,*是接收数据的类(即上面定义的Translation类)
    // 如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call<ResponseBody>
}
Retrofit与其他框架的对比
Retrofit中URL组成
Url 由 BaseUrl 和 path组成。BaseUrl在 Rotrofit 实例化时进行设置。path在接口描述中设置。
BaseUrl = “ http://host:port/aaa/ ”;
path =  “pathname ”;
Retrofit注解类型
1.注解网络请求方法
2.注解---标记类
3.注解---网络请求参数
Retrofit注解详解
1.请求方法---注解
1.1@HTTP注解的作用
@HTTP注解可以替换@GET、@POST、@PUT、@DELETE、@HEAD注解,及更多功能扩展。
public interface GetRequest_Interface {
    /**
     * method:网络请求的方法(区分大小写)
     * path:网络请求地址路径
     * hasBody:是否有请求体
     */
    @HTTP(method = "GET", path = "blog/{id}", hasBody = false)
    Call<ResponseBody> getCall(@Path("id") int id);
    // {id} 表示是一个变量
    // method的值,retrofit不会做检查处理,所以要自行保证准确
}
2.标记类---注解
2.1 @FormUrlEncode
    @FormUrlEncode 表示请求体是一个Form表单,需要用 @Filed 来注解每个键值对的键名称,随后的对象需要提供键值对的 值。它用于Post请求,不能用于Get请求,因为Get请求中没有请求体。
public interface GetRequest_Interface {
    /**
     * @FormUrlEncoded表明是一个表单格式的请求(application/x-www-form-urlencoded)
     * Field("username") 表示将后面的String name 中name的取值作为 username 的值
     */
     @POST("/form")
     @FormUrlEncoded
     Call<ResponseBody> testFormUrlEncoded(
        @Field("username") String name,
        @Field("age") int age
     );
}

//具体使用
GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
Call<ResponseBody> call1 = service.testFormUrlEncoded("Carson", 24);

2.2@Multipart

    @Multipart表示请求体是一个文件上传的Form表单,需要用@Part来注解每个键值对的键名称,随后的对象需要提供键值对的值。
public interface GetRequest_Interface {
   /**
    * @Part后面支持三种类型:RequestBody、okhttp3.MultipartBody.Part、任意类型;
    * 除了okhttp3.MultipartBody.Part类型以外,其它类型都必须带上表单字段,
    * okhttp3.MultipartBody.Part中已经包含了表单字段的信息。
    */
    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpload(
        @Part("name") RequestBody name, 
        @Part("age") RequestBody age, 
        @Part MultipartBody.Part file
    );
}

// 具体使用
GetRequest_Interface mService = retrofit.create(GetRequest_Interface.class);
MediaType textType = MediaType.parse("text/plain");
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");
RequestBody file = RequestBody
                .create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容");
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call<ResponseBody> call3 = mService.testFileUpload(name, age, filePart);
3.网络请求参数---注解
3.1 @Headers
@Headers 用于在描述接口中 静态添加请求头
public interface GetRequest_Interface {
    @Headers(
        "Authorization: authorization”,
        "Accept: application/vnd.yourapi.v1.full+json",
        "User-Agent: Your-App-Name"
    )
    @GET("user")
    Call<User> getUser()
}
3.2  @Header
@Header 用于动 态添加请求头 ,即需要添加的请求头,会作为参数传入
public interface GetRequest_Interface {
    @GET("user")
    Call<User> getUser(
        @Header("Authorization") String authorization
    )
}
3.3 @Body
@Body用于非表单请求体, 并以Post方式提交自定义的数据类型 。但是如果提交的是一个Map集合,那么@Body的作用就相当于@Field,不过此时的map需要被FormBody.Builder处理成符合Okhttp的表单。
public interface GetRequest_Interface {
    @FormUrlEncoded
    @POST("book/reviews")
    Call<String> addReviews(@Body Reviews reviews);
}

public class Reviews {
    public String book;
    public String title;
    public String content;
    public String rating;
}

//具体使用
Reviews reviews = new Reviews();
reviews.setBook(“百科全书”);
reviews.setTitle(“标题”);
reviews.setContent(“描述内容”);
reviews.setRating(“hello!”);
Call<ResponseBody> call = service.addReviews(reviews);

//Map处理过程
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
3.4 @Field & @FieldMap
@Field和FieldMap与标记类@FormUrlEncode配合使用,作为发送Post请求时提交请求参数的表单字段。
public interface GetRequest_Interface {
    /**
     * 表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
     * Field("username")表示将后面的String name中name的取值作为 username 的值
     */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrlEncoded1(
        @Field("username") String name,
        @Field("age") int age
    );

    /**
     * Map的key作为表单的键
     */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrlEncoded2(
        @FieldMap Map<String, Object> map
    );
}

//具体使用
// @Field
Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
// @FieldMap
// 实现的效果与上面相同,但要传入Map
Map<String, Object> map = new HashMap<>();
map.put("username", "Carson");
map.put("age", 24);
Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
3.5 @Part & @PartMap
@Part和@PartMap与标记类@Multipart配合使用, 作为发送Post请求时提交请求参数的表单字段。适用于文件上传的场景。
public interface GetRequest_Interface {
    /**
     * @Part后面支持三种类型:RequestBody、 okhttp3.MultipartBody.Part、任意类型:
     * 除了okhttp3.MultipartBody.Part以外,其它类型都必须带上表单字段,
     * okhttp3.MultipartBody.Part中已经包含了表单字段的信息。
     */
    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpload1(
        @Part("name") RequestBody name, 
        @Part("age") RequestBody age,
        @Part MultipartBody.Part file
    );
    /**
     * PartMap 注解支持一个Map作为参数,支持RequestBody类型,
     * 如果有其它的类型,会被retrofit2.Converter转换,如后面会介绍的,
     * 使用com.google.gson.Gson的retrofit2.converter.gson.GsonRequestBodyConverter
     * 所以MultipartBody.Part就不适用了,所以文件只能用@Part MultipartBody.Part
     */
    @POST("/form")
    @Multipart
    Call<ResponseBody> testFileUpload2(
        @PartMap Map<String, RequestBody> args, 
        @Part MultipartBody.Part file
    );
}

// 具体使用
MediaType textType = MediaType.parse("text/plain");
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");
RequestBody file = RequestBody
                .create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容");
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);

// @Part
Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);
ResponseBodyPrinter.printResponseBody(call3);

// @PartMap
// 实现和上面同样的效果
Map<String, RequestBody> fileUpload2Args = new HashMap<>();
fileUpload2Args.put("name", name);
fileUpload2Args.put("age", age);
Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); 
// 单独处理文件
ResponseBodyPrinter.printResponseBody(call4);
3.6 @Query & @QueryMap
@Query和@QueryMap用于@Get方法的查询参数 (Query = Url中?后面的 key-value)
public interface GetRequest_Interface {
    @GET("book/search")    
    Call<ResponseBody> cate1(
        @Query("username") String username,
        @Query(“age”) int age
    );
   
    @GET("book/search")
    Call<ResponseBody> cate2(
        @QueryMap Map<String, Object> map
    );

    Call<ResponseBody> cate3(
        @Query("list") List<String> strList,
    );
}

//具体使用
// @Query
Call<ResponseBody> call1 = service.cate1("Carson",19);
// @QueryMap
// 实现的效果与上面相同,但要传入Map
Map<String, Object> map = new HashMap<>();
map.put("username", "Carson");
map.put("age", 24);
Call<ResponseBody> call2 = service.cate2(map);
3.7 @Path
@Path 用作Url地址的缺省值。Post、Get、Put、Delete中都可以使用
public interface GetRequest_Interface {
    @GET("users/{user}/repos")
    Call<ResponseBody> getBlog(@Path("user") String user );
    // 访问的API是:https://api.github.com/users/{user}/repos
    // 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用)
}

//具体使用
Call<ResponseBody> call = service.getBlog(“carson”);
//则描述的接口为:“users/carson/repos”。
3.8 @Url
@Url 用于在网络请求的时候,直接传入一个请求的Url变量,用于Url设置。
public interface GetRequest_Interface {
    @GET
    Call<ResponseBody> testUrlAndQuery(
        @Url String url, 
        @Query("showAll") boolean showAll
    );
    // 当@HTTP、@POST、@GET中设置了path时,@GET传入的URL就可以省略
    // 当GET、POST...HTTP等方法中没有设置Url时,则必须使用 {@link Url}提供
}

//具体使用
Url url = “http://www.baidu.com/abc”
Call<ResponseBody> call = service.testUrlAndQuery(url, true);
//则描述的接口为:“http://www.baidu.com/abc?showAll=true”。

自定义Interceptor拦截器

创建一个自定义的Interceptor拦截器,然后在创建Retrofit实例的地方通过addInterceptor()进行添加,通过它我们可以实现一些拦截的操作,比如下面:我们想要拦截每一次请求,添加一个公共的请求参数。
//自定义拦截器——添加公共参数
public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl httpUrl = request.url().newBuilder()
                .addQueryParameter("token", "tokenValue")
                .build();
        request = request.newBuilder().url(httpUrl).build();
        return chain.proceed(request);
    }
}

//自定义拦截器—添加 header
//添加header参数Request提供了两个方法,一个是header(key, value),
//另一个是.addHeader(key, value),两者的区别是,header()如果有重名的将会覆盖,
//而addHeader()允许相同key值的header存在
public class RequestInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        Request request = original.newBuilder()
            .header("User-Agent", "Your-App-Name")
            .header("Accept", "application/vnd.yourapi.v1.full+json")
            .method(original.method(), original.body())
            .build();
        return chain.proceed(request);
    }
}

//添加拦截器Interceptor
private static OkHttpClient getNewClient(){
  return new OkHttpClient.Builder()
    .addInterceptor(new CustomInterceptor())
    .addInterceptor(new RequestInterceptor())
    .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
    .build();
}
Retrofit官方提供了一个方便查看日志的Interceptor拦截器,方便的控制打印信息的类型。HttpLoggingInterceptor提供4种控制打印信息类型的等级,分别是:NONE、BASIC、HEADERS、BODY。
//引入依赖
implement 'com.squareup.okhttp3:logging-interceptor:3.4.1’
//具体使用
private static OkHttpClient getNewClient(){
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    return new OkHttpClient.Builder()
           .addInterceptor(logging)
           .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
           .build();
}

Retrofit解析器与适配器

1.数据解析器 Converter,Retrofit支持多种解析器
   
2.网络请求适配器 CallAdapter,Retrofit支持多种网络请求适配器
   

Retrofit中的API

Call<ResponseBody> call = servers.lookBookDetail(“参数”);
call.enqueue(new Callback<Translation>() {
    //请求成功时回调
    @Override
    public void onResponse(Call<Translation> call, Response<Translation> response) {
        // 对返回数据进行处理
        response.body().show();
    }
    //请求失败时候的回调
    @Override
    public void onFailure(Call<Translation> call, Throwable throwable) {
         System.out.println("连接失败");
    }
});
1.异步请求
   call.enqueue();
2.同步请求
   call.execute();
3.取消请求
    call.cancel();
4.对数据进行处理
   respose.body().show();

Retrofit的使用

1.在app模块的build.gradle文件中引入Retrofit框架。
implement 'com.squareup.retrofit2:retrofit:2.0.2’
implement 'com.squareup.retrofit2:converter-gson:2.0.2'
2.自定义数据接收实体类
3.创建用于描述网络请求的接口
4.创建Retrofit对象
5.创建网络请求接口实例
6.发送网络请求
7.处理返回数据、
//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
  .baseUrl(""http://fanyi.youdao.com/"")
  .addConverterFactory(ProtoConverterFactory.create()) // 支持Prototocobuff解析
  .addConverterFactory(GsonConverterFactory.create()) // 支持Gson解析
  .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava
  .build();
//创建 网络请求接口 的实例
PostRequest_Interface request = retrofit.create(PostRequest_Interface.class);
//对网络请求进行封装
Call<Translation1> call = request.getCall("I love you”);
//发送网络请求(异步)
call.enqueue(new Callback<Translation1>() {
//请求成功时回调
    @Override
    public void onResponse(Call<Translation1> call, Response<Translation1> response) {
        // 步骤7:处理返回的数据结果:输出翻译的内容  
        System.out.println(response.body().getTranslateResult().get(0).get(0).getTgt());
    }
    //请求失败时回调
    @Override
    public void onFailure(Call<Translation1> call, Throwable throwable) {
        System.out.println("请求失败");
        System.out.println(throwable.getMessage());
    }
});

Retrofit实现文件上传

public interface FileUploadService {  
    // 上传单个文件
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadFile(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file);

    // 上传多个文件
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadMultipleFiles(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file1,
            @Part MultipartBody.Part file2);
}
//Retrofit上传文件的工具类
public class retrofitFileUtil{
    public static final String MULTIPART_FORM_DATA = "multipart/form-data”;

    private RequestBody createPartFromString(String descriptionString) {  
        return RequestBody.create(
                 MediaType.parse(MULTIPART_FORM_DATA), descriptionString);
    }

    private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {  
        File file = FileUtils.getFile(this, fileUri);
        // 为file建立RequestBody实例
        RequestBody rf = RequestBody.create(MediaType.parse(MULTIPART_FORM_DATA), file);
        // MultipartBody.Part借助文件名完成最终的上传
        return MultipartBody.Part.createFormData(partName, file.getName(), rf);
    }
}
Uri file1Uri = ... // 从文件选择器或者摄像头中获取
Uri file2Uri = …

// 创建上传的service实例
FileUploadService service = ServiceGenerator.createService(FileUploadService.class);
// 创建文件的part (photo, video, ...)
MultipartBody.Part body1 = prepareFilePart("video", file1Uri);  
MultipartBody.Part body2 = prepareFilePart("thumbnail", file2Uri);
// 添加其他的part
RequestBody description = createPartFromString("hello, this is description speaking");
// 最后执行异步请求操作
Call<ResponseBody> call = service.uploadMultipleFiles(description, body1, body2);  
call.enqueue(new Callback<ResponseBody>() {  
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        Log.v("Upload", "success");
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.e("Upload error:", t.getMessage());
    }
});

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值