Retrofit学习笔记
Retrofit基础
- Retrofit 中使用注解的方式来区分请求类型,比如@GET("/record")表示一个GET请求,要以 / 开头,会拼接到基本URL后面,record为接口地址。各个格式和含义如下:
例如,GET请求(其他请求类似):
@GET("/apistore/mobilenumber/mobilenumber")
Call<PhoneResult> getResult(@Header("apikey") String apikey, @Query("phone") String phone);
- 服务器接口类型
- 直接请求型
@GET("/record")
Call<PhoneResult> getResult();
组合后直接请求
@GET("/result/{id}") //其中{id}中的id在实际使用时填写实际值即可.
Call<PhoneResult> getResult(@Path("id") String id);
- 带参查询型
@GET("/otn/lcxxcx/query") //某个接口
Call<Result> query(@Query("purpose_codes") String codes);
- 带Header型
@POST("/info")
Call<Object> updateInfo(@Header("device") String device, @Header("version") int version,
@Field("id") String id);
- 注解
1)、Query注解
interface QueryGET{
@GET("/sheet")
String getString(@Query("name")String name,@Query("age") int age);
}
- query 访问的参数会添加到路径(path)的后面。encodeNames=true表示对url的query进行url编码,同理还有encodeValues. 这2个的值默认都是true。
- 实际访问的地址是“http://tieba.baidu.com/sheet?name=xxx&age=xxx ”
2)、Field和Part注解
我们也可以在post请求的时候发送form-data和multipart-data.
表单数据要使用@FormUrlEncoded注解.每一对键值对都要用@Field进行注解, 包括名字和value对象的值.
@FormUrlEncoded
@POST("/user/edit")
User updateUser(@Field("first_name") String first, @Field("last_name") String last);
用@Multipart注解来发送multipart-data,每一个part用@part注解.
@Multipart
@PUT("/user/photo")
User updateUser(@Part("photo") TypedFile photo, @Part("description") TypedString description);
3)、Header注解
header分为key和value都固定,静态Header注解方法和动态Header注解方法。注意header不会相互覆盖。
- 静态header
interface FixedHeader{
@Headers({ //静态Header,先写好
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("/")
Response getResponse();
}
- 动态header
interface DynamicHeader{
@Headers("Cache-Control: max-age=640000") //静态Header
@GET("/")
Response getResponse(@Header("header1")String header1,@Header("header2")String header2); //动态Header,其value值可以在调用这个方法时动态传入.
}
- 同步和异步
- 同步
有返回值的方法是同步执行的,如:
interface Client{
@GET("/user/{id}/photo")
Photo getUserPhoto(@Path("id") int id);
}
- 异步
采用异步执行的话,需要方法的最后一个参数是CallBack且返回值类型是void
interface AsychronousClient{
@GET("/")
void getResponse(Callback<String> callback); //如果使用异步的方式的话,特别注意这里方法的返回值必须是void,Response转化成的对象类型写在CallBack<T>的泛型中.
}
注意,异步方式的retrofit网络访问还是在子线程中运行的.但CallBack的success()和failure()方法是在主线程中运行的.(通过Android的Hanlder机制实现的)
Retrofit retrolfit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create()) //解析方法 用gson把ResponseBody转为我们泛型中的类型String
.baseUrl(BASE_URL)
.build();
AsychronousClient create= retrolfit.create(AsychronousClient .class);
create.getResponse(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
}
@Override
public void onFailure(Call<String> call, Throwable t) {
}
});
- 使用示例
- 调用过程:
1.创建Retrofit对象
2.创建访问API的请求
3.发送请求
4.处理结果
public interface BlogService {
@GET("blog/{id}") //这里的{id} 表示是一个变量
Call<ResponseBody> getFirstBlog(@Path("id") int id); /** 这里的id表示的是上面的{id} */
}
public class Example01 {
public static void main(String[] args) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
.build(); //创建Retrofit对象
BlogService service = retrofit.create(BlogService.class);
Call<ResponseBody> call = service.getFirstBlog(2); //创建访问API的请求
// 用法和OkHttp的call如出一辙
// 不同的是如果是Android系统回调方法执行在主线程
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的22个注解详解
- Http请求方法
以上表格中的除HTTP以外都对应了HTTP标准中的请求方法,而HTTP注解则可以代替以上方法中的任意一个注解,有3个属性:method、path,hasBody,下面是用HTTP注解实现上面Example01.java 的例子。
public class Example02 {
public interface BlogService {
/**
* method 表示请的方法,不区分大小写
* path表示路径
* hasBody表示是否有请求体
*/
@HTTP(method = "get", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getFirstBlog(@Path("id") int id);
}
public static void main(String[] args) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
.build();
BlogService service = retrofit.create(BlogService.class);
Call<ResponseBody> call = service.getFirstBlog(2);
ResponseBodyPrinter.printResponseBody(call);
}
}
- 标记类
使用示例:
public class Example03 {
public interface BlogService {
/**
* {@link FormUrlEncoded} 表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中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);
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
/**
* PartMap 注解支持一个Map作为参数,支持 {@link RequestBody } 类型,
* 如果有其它的类型,会被{@link retrofit2.Converter}转换,如后面会介绍的 使用{@link com.google.gson.Gson} 的 {@link retrofit2.converter.gson.GsonRequestBodyConverter}
* 所以{@link MultipartBody.Part} 就不适用了,所以文件只能用<b> @Part MultipartBody.Part </b>
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file);
}
public static void main(String[] args) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
.addConverterFactory(GsonConverterFactory.create())
.build();
BlogService service = retrofit.create(BlogService.class);
// 演示 @FormUrlEncoded 和 @Field
Call<ResponseBody> call1 = service.testFormUrlEncoded1("怪盗kidou", 24);
ResponseBodyPrinter.printResponseBody(call1);
// 演示 @FormUrlEncoded 和 @FieldMap
// 实现的效果与上面想同
Map<String, Object> map = new HashMap<>();
map.put("username", "怪盗kidou");
map.put("age", 24);
Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
ResponseBodyPrinter.printResponseBody(call2);
//===================================================
MediaType textType = MediaType.parse("text/plain");
RequestBody name = RequestBody.create(textType, "怪盗kidou");
RequestBody age = RequestBody.create(textType, "24");
RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容");
// 演示 @Multipart 和 @Part
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);
ResponseBodyPrinter.printResponseBody(call3);
//===================================================
// 演示 @Multipart 和 @PartMap
// 实现和上面同样的效果
Map<String, RequestBody> fileUpload2Args = new HashMap<>();
fileUpload2Args.put("name", name);
fileUpload2Args.put("age", age);
//这里并不会被当成文件,因为没有文件名(包含在Content-Disposition请求头中),但上面的 filePart 有
//fileUpload2Args.put("file", file);
Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); //单独处理文件
ResponseBodyPrinter.printResponseBody(call4);
}
}
- 注解类
@Body用于非表单请求,比如json请求,注解实体,然后添加Gson转换就会自动转成json格式数据。
public interface Api {
//发送json数据形式的post请求,把网络请求接口的后半部分openapi/api/v2写在里面
//Get是请求数据实体类,Take接受数据实体类
@POST("openapi/api/v2") //Post请求发送数据
Call<Take> request(@Body Ask ask);//@body即非表单请求体,被@Body注解的ask将会被Gson转换成json发送到服务器,返回到Take。 // 其中返回类型为Call<*>,*是接收数据的类
}
Headers/Header:
public interface BlogService {
@GET("/headers?showAll=true")
@Headers({"CustomHeader1: customHeaderValue1", "CustomHeader2: customHeaderValue2"})
Call<ResponseBody> testHeader(@Header("CustomHeader3") String customHeaderValue3);
}
其他用法在上面各个例子有涉及。
- 与RxJava结合使用(把call变成observable对象)
1)、添加依赖
compile 'io.reactivex:rxjava:x.y.z'
compile 'io.reactivex:rxandroid:1.0.1'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' //**新加的,结合使用需要**
2)、service接口
interface MyService {
@GET("user/login" )
Observable<UserInfo> login( //注意返回是Observable!!!
@Query("username") String username,
@Query("password") String password
);
}
3)、完成一个网络请求
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//**新的配置**
.baseUrl(BASE_URL)
.build();
MyService service = retrofit.create(MyService.class);
service.login(phone, password) //获取Observable对象
.subscribeOn(Schedulers.newThread())//请求在新的线程中执行
.observeOn(Schedulers.io()) //请求完成后在io线程中执行
.doOnNext(new Action1<UserInfo>() {
@Override
public void call(UserInfo userInfo) {
saveUserInfo(userInfo);//保存用户信息到本地
}
})
.observeOn(AndroidSchedulers.mainThread())//最后在主线程中执行
.subscribe(new Subscriber<UserInfo>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
//请求失败
}
@Override
public void onNext(UserInfo userInfo) {
//请求成功 }
});