Retrofit

来源:互联网 发布:怎么修改淘宝密码 编辑:程序博客网 时间:2024/06/02 01:06

Retrofit 是Square公司推出的简化HTTP请求的第三方库, 是对其公司另一网络请求库OkHttp的封装

实现了对响应数据解析的封装, 可以不需要自己去解析网络请求回来的数据. 使用方法采用注解的形式.

想要了解Retrofit的使用, 需要先了解Okhttp的用法. 因为Retrofit是基于Okhttp的封装. 同样也可以用Okhttp的方法.

参考文档:

官方

  • GitHub
  • 使用指南
  • 开发文档

博客

  • 深入浅出Retrofit
  • 你真的会用Retrofit2吗?

演示

这里我以获取网站内容为例子

完整接口链接

http://liangjingkanji.coding.me/2017/03/03/TabLayout/

添加依赖

建议以官方GitHub最新版为准

compile 'com.squareup.retrofit2:retrofit:2.2.0'

创建实例

通过Retrofit的构造器创建实例对象

Retrofit retrofit = new Retrofit.Builder()        .baseUrl("http://liangjingkanji.coding.me/")         .build();
  • baseUrl 一般存放的是服务器的域名, 记住必须以”/”结尾, 否则报异常

注意: 在Retrofit2版本以前baseUrl通过加不加”/”来判断@Path是绝对路径还是相对路径. 但是在2.0强制要求必须以”/”结尾.

创建接口

在Retrofit中每个接口都对应一个网络请求, 该接口是用于设置请求的参数或者路径以及响应体类型

public interface BlogService {    @GET("2017/03/03/{index}")     Call<ResponseBody> getBlog(@Path("index") String index); }
  • @GET(“2017/03/03/{index}”) 表示以GET方式请求链接. 后面的字符串是拼接地址. “{}”大括号内部是占位符的含义. 最终会用getBlog里面的参数替代.
  • @Path(“index”) 表示其修饰的参数String index 将会替代之前提到的占位符”{index}”

创建服务

通过接口的字节码创建服务

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

执行回调

通过接口的方法得到回调

Call<ResponseBody> call = service.getBlog(2); // 得到回调call.enqueue(new Callback<ResponseBody>() { // 执行回调  // 成功回调    @Override    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {        try {            System.out.println(response.body().string()); // 打印响应体        } catch (IOException e) {            e.printStackTrace(); // 读取响应体失败        }    }  // 失败回调    @Override    public void onFailure(Call<ResponseBody> call, Throwable t) {        t.printStackTrace(); // 打印请求错误异常信息    }});

全部请求方法

retrofit支持六种请求方式, 通过注解的方式使用. 上面的示例我们就使用了@GET 注解

  • GET
  • POST
  • PUT
  • DELETE
  • HEAD
  • OPTIONS
  • HTTP

其中HTTP是以通过值来决定请求方式的注解

public interface BlogService {    /**     * method 表示请求的方法,区分大小写     * path表示路径     * hasBody表示是否有请求体     */    @HTTP(method = "GET", path = "blog/{id}", hasBody = false)    Call<ResponseBody> getBlog(@Path("id") int id);}

这里我只讲解常用的GET和POST请求方式

GET请求

关键注解: @GET

可选参数: String path 表示一个绝对或者相对/完整的URL路径

这里请求方式注解的参数虽然说都是可选参数, 但是如果你完全不写还是会报错的. 除非你在服务接口的方法参数里面加个@URL 注解指定了路径.

如果你想直接用baseUrl的路径可以使用@GET("/")或者@GET(".")代表使用baseUrl作为完整路径. POST请求方式同样处理.

URL拼接

GET请求本身就是拼接URL. 所以你可以在路径里面直接写请求参数.

@GET("users/list?sort=desc")

如果在想传入值的情况下可以使用以下注解

关键注解 @Query 用于修饰方法参数

必须参数: String value 参数名

可选参数: boole encoded 是否对参数进行URLEncode编码

这里我没有把接口的路径写到@GET注解里面. 这种写法和之前示例里面的一样.

public interface GitHubService {    @GET    Call<String> request(@Query("key") String value @URL String path);}

如果是参数名相同值不同的多个参数可以用可变参数写. 这算是数组类型参数.

后面这种可变参数的写法我不会再提.

 @GET Call<ResponseBody> list(@Query("category") String... categories, @URL String path);

结果

路径/list?category=bar&category=baz.

如果GET是多个参数一个个写是很麻烦的. 所以需要使用到Map集合

关键注解: @QueryMap 修饰Map集合

可选参数: boolean encoded 是否对参数进行URLEncode编码

 @GET("/search") Call<ResponseBody> list(@QueryMap Map<String, String> filters);

结果

路径 /search?foo=bar&kit=kat.

**注:**URLEncode编码是对URL地址中的特殊字符进行编码. 防止被服务器错误识别. 例如”&”默认为参数拼接的含义. 如果请求参数中包含这个特殊字符怎么办? URLEcode就会将其换成其他字符. 详情可以Google.

POST请求

关键注解: @POST

可选参数: String path 绝对或者相对/完整的URL路径

下面我会介绍Post请求的几种请求方式. 可以归纳为:

  1. 表单
  2. 字符串

FormUrl提交

即最常见的表单提交. 用于提交键值对的基本类型的参数. 注意不能上传文件. 也就是说@Field只能修饰基本数据类型.

关键注解: @FormUrlEncoded

@POST("/form")@FormUrlEncodedCall<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);

单参数

POST请求肯定是要带有参数的. POST参数注解和GET参数注解类似

关键注解: @Field

必须参数: String value 表单参数的名字

可选参数: boolean encoded 是否对参数进行URLEncode编码

 @FormUrlEncoded @POST("/") Call<ResponseBody> example(     @Field("name") String name,     @Field("occupation") String occupation);

多参数

使用Map集合参数提交

关键注解: @FieldMap

可选参数: boolean encoded 是否对参数进行URLEncode编码

 @FormUrlEncoded @POST("/things") Call<ResponseBody> things(@FieldMap Map<String, String> fields);

Multipart提交

多类型提交一般用于文件. 也可以作为表单提交键值对

关键注解: @Multipart

@POST("/form")@MultipartCall<ResponseBody> testFileUpload3(@PartMap Map<String, RequestBody> args);

单参数

关键注解: @Part

可选参数:

  • String value 参数名
  • String encoding
@POST("/form")@MultipartCall<ResponseBody> testFileUpload2(@Part MultipartBody.Part file);

多参数

关键注解: @PartMap

可选参数: String encoding

 @Multipart @POST("/upload") Call<ResponseBody> upload(     @Part("file") RequestBody file,     @PartMap Map<String, RequestBody> params);

关键注解: @Multipart

流类型提交

关键注解: @Streaming

请求参数

除了上面所提到的提交参数意外还有

路径拼接

GET注解后面一般不是都会有个相对路径的字符串嘛. 这个字符串里面可以通过写{}包裹任意内容. 被包裹的都是占位符. 最终会被Path注解修饰的参数替代. 最开始的示例就是用了这个注解.

关键注解: @Path

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors")List<Contributor> repoContributors(       @Path("owner") String owner,       @Path("repo") String repo);}

请求体

使用一个对象作为请求体提交, 例如使用Json进行参数的提交. 该请求体同样可以作为@GET请求的参数提交.

关键注解: @Body

@POST("users/new")Call<User> createUser(@Body User user);

这个Body修饰的参数要求必须是Retrofit指定的响应体转换类型. 也就是说要求请求体和响应体都要求同样. 否则只能用Response作为请求体.

请求头

单请求头

关键注解: @Header

必须参数: String value 请求头参数

 @GET("/") Call<ResponseBody> foo(@Header("Accept-Language") String lang);

多请求头

使用String[] 作为请求头. 注意只有@Headers可以单独使用. 其他的请求头注解都只能修饰方法参数

关键注解: @Headers

必须参数: String[] value 请求头参数

单请求头

 @Headers("Cache-Control: max-age=640000") @GET("/")

多请求头

 @Headers({   "X-Foo: Bar",   "X-Ping: Pong" }) @GET("/")

还可以使用Map集合作为请求头参数

关键注解: @HeaderMap

 @GET("/search") void list(@HeaderMap Map<String, String> headers);

Response 响应参数

关键类: Response

public static <T> Response<T> success(T body)public static <T> Response<T> success(T body,                                      okhttp3.Headers headers)public static <T> Response<T> success(T body,                                      okhttp3.Response rawResponse)public static <T> Response<T> error(int code,                                    okhttp3.ResponseBody body)public static <T> Response<T> error(okhttp3.ResponseBody body,                                    okhttp3.Response rawResponse)public okhttp3.Response raw()// 状态码public int code()// 响应消息, 如果未知返回nullpublic String message()public okhttp3.Headers headers()// 是否成功, 状态码在200~300之间([200..300))public boolean isSuccessful()// 得到响应体, 该响应体属于泛型, 详情介绍看Retrofit转换器public T body()// 访问失败返回的响应体, 即状态码不在200~300之间public okhttp3.ResponseBody errorBody()

转换器

前面提过Retrofit支持直接返回你想要的类型对象. 例如返回的Json数据直接返回JsonBean对象. 而不是Response对象. 同样你想直接返回String类型也行.

除了添加Retrofit依赖外, 还需要添加转换响应体的依赖包. 官方提供六种常用转换库

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

这里我使用了Gson转换器进行讲解

关键类

Gson

添加Gson转换器的依赖, 这里的依赖包版本号跟随Retrofit即可

compile 'com.squareup.retrofit2:converter-gson:2.2.0'

创建接口. “.”的路径表示使用baseUrl作为完整路径. 这里的TimeBean是我创建的一般的JsonBean类

public interface InterfaceService {    @GET(".")    Call<TimeBean> getServerTime();}

创建实例的时候增加一个方法addConverterFactory

Retrofit retrofit = new Retrofit.Builder()    .baseUrl("http://mob.mgtvshop.com/interface/get_time/")    .addConverterFactory(GsonConverterFactory.create()) // 添加转换器    .build();InterfaceService service = retrofit.create(InterfaceService.class);Call<TimeBean> serverTime = service.getServerTime();serverTime.enqueue(new Callback<TimeBean>() {  @Override  public void onResponse(Call<TimeBean> call, Response<TimeBean> response) {        // response的body()将直接返回Jsonbean类    System.out.println(response.body().getMsg());   }  @Override  public void onFailure(Call<TimeBean> call, Throwable t) {  }});

注:如果返回的Json不能被解析. 则返回null. 报空指针异常. 建议进行异常捕捉.

Retrofit

Build

public Retrofit.Builder baseUrl(okhttp3.HttpUrl baseUrl)// 字符串链接必须以 "/"结尾, 一般为域名public Retrofit.Builder baseUrl(String baseUrl)// 设置一个Okhttp客户端public Retrofit.Builder client(okhttp3.OkHttpClient client)// 设置回调实例public Retrofit.Builder callFactory(okhttp3.Call.Factory factory)// 添加序列化或反序列化转换器public Retrofit.Builder addConverterFactory(Converter.Factory factory)public Retrofit.Builder addCallAdapterFactory(CallAdapter.Factory factory)public Retrofit.Builder callbackExecutor(Executor executor)public Retrofit.Builder validateEagerly(boolean validateEagerly)public Retrofit build()

Retrofit

public <T> T create(Class<T> service)

请求网络

和Okhttp不同的是Retrofit的回调方法都已在主线程内. 可以直接更新UI.

Call

该方法和okHttp的Call类没什么区别.

同步执行

注意, Android不支持同步网络请求. 如果要使用需要处理 NetworkOnMainThreadException 异常

Response<T> execute()             throws IOException

示例:

try {          Response<ResponseBody> bodyResponse = call.execute();          String body = bodyResponse.body().string();//获取返回体的字符串          Log.i("wxl", "body=" + body);      } catch (IOException e) {          e.printStackTrace();      }

异步执行

void enqueue(Callback<T> callback)

示例:

call.enqueue(new Callback<ResponseBody>() {            @Override            public void onResponse(Response<ResponseBody> response) {                try {                    Log.i("wxl", "response=" + response.body().string());                } catch (IOException e) {                    e.printStackTrace();                }            }            @Override            public void onFailure(Throwable t) {                Log.i("wxl", "onFailure=" + t.getMessage());            }        });

更多方法

// 是否执行了网络请求boolean isExecuted()// 取消网络请求void cancel()// 是否执行了取消网络请求boolean isCanceled()// 创建新的网络请求Call<T> clone()// 得到请求对象okhttp3.Request request()

网络请求的回调

Interface Callback<T>

实现接口需要重写两个方法:

成功:

void onResponse(Call<T> call,                Response<T> response) // 成功时返回的响应体

失败:

该失败指的是服务器错误或者因为异常请求的原因. 例如Json解析错误也会回调该方法

void onFailure(Call<T> call,               Throwable t) // 失败时抛出的异常