Retrofit是什么
retrofit是一个restful的http网络请求框架的封装,但网络请求不是由retrofit来完成的,它只是封装了请求参数、header、url、返回结果等信息,而真正处理网络请求的是由OkHttp来完成的。
基础使用
- 1、导包
//网络请求相关 implementation
"com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:retrofit-
mock:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:converter-
gson:$rootProject.retrofitVersion"
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
implementation "com.squareup.retrofit2:converter-
scalars:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:adapter-
rxjava2:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:converter-
gson:$rootProject.retrofitVersion"
- 2、定义一个Http API接口类
interface WanAndroidApi {
@GET("project/tree/json")
Call<ProjectBean> getProject();
}
- 3、使用Retrofit类生成WanAndroidApi 接口实现
Retrofit retrofit = new Retrofit.Builder()//建造者模式 .baseUrl("https://www.wanandroid.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
WanAndroidApi wanAndroidApi =
retrofit.create(WanAndroidApi.class);//代理实例
- 4、发送HTTP请求,返回Response可以同步或者异步处理
Call<ProjectBean> call = wanAndroidApi.getProject();//获取具体的某个业务 //同步请求
Response<ProjectBean> response = call.execute();
ProjectBean projectBean = response.body();
//异步请求
call.enqueue(new Callback<ProjectBean>() {
@Override
public void onResponse(final Call<ProjectBean> call, final
Response<ProjectBean> response) {
Log.i("Zero","response: " + response.body());
}
@Override
public void onFailure(final Call<ProjectBean> call, final
Throwable t) {}
});
我们知道retrofit是通过注解配置请求的,在源码里我们可以看到一共有26个注解,我们最常用的肯定是GET和POST注解了。
/** Make a GET request. */
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
/**
* A relative or absolute path, or full URL of the endpoint. This value is optional if the first
* parameter of the method is annotated with {@link Url @Url}.
*
* <p>See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
* this is resolved against a base URL to create the full endpoint URL.
*/
String value() default "";
}
在Retrofit中其实是通过注解 + 泛型 + 动态代理来实现的,并且其中使用了非常多的设计模式,具体我们在源码分析的时候再展开讲。我们回到GET注解:1、@Target(METHOD):代表是一个方法;@Target(PARAMETER):代表是一个参数,2、Retention(RUNTIME):并且是在运行期的注解。我们都知道运行期的注解,我们是需要通过反射获取他的内容的。在Retrofit中所有的26个注解都是运行期的注解。Retrofit在运行期的时候会去动态的解析标记上这些注解的内容。例如我们的GET注解,Retrofit在运行期的时候会去动态的解析标记上@GET,然后获取到"project/tree/json"这些值
interface WanAndroidApi {
@GET("project/tree/json")
Call<ProjectBean> getProject();
}
在retrofit中注解可以分成三类:1、请求方法类 2、标志类 3、参数类
1、请求方法类注解
image.png- 分别对应HTTP的请求方法
- 接收一个字符串表示接口的path,与baseUrl组成完整的请求Url
其中我们需要注意的是HTTP注解,它是一个通用注解,可以替换以上所有的注解,其拥有method, path, hasBody三个属性。例如上面的get请求也可以这样写
@GET("project/tree/json")
fun getProject(): Call<ProjectBean>
@HTTP(method = "get",path = "project/tree/json",hasBody = false)
fun getProject(): Call<ResponseBody>
开发过后端接口的小伙伴看到这个肯定会觉得很熟悉,是不是和SpringBoot的写法很像,细心的小伙伴肯定也注意到了,顺带提一嘴,第一种Call里写的是ProjectBean,另外一种Call写了ResponseBody,其实这两种都可以,ResponseBody是更原始的方式,而你写了具体的实体类的话,retrofit会在内部帮你解析成ProjectBean,其实就是在你构建一个retrofit对象的时候.addConverterFactory(GsonConverterFactory.create())添加了这个GSON转化器,当然你觉得自己很牛逼想自己解析的话可以写成ResponseBody。转换器也是retrofit里很好用的东西,例如我们熟悉的GSON转化器,RxJava转化器,都可以在构建retrofit对象的时候添加进去。
2、参数类注解
image.png- Headers
//使用 `@Headers`注解设置固定的请求头,不同的请求头不会相互覆盖,即使名字相同。
@Headers("Cache-Control: max-age=640000")
@GET("project/list")
Call<ProjectBean> getMsg1();
@Headers({ "Accept: application/vnd.github.v3.full+json","User-Agent:
Retrofit-Sample-App"})
@GET("project/{username}")
Call<ProjectBean> getMsg2(@Path("username") String username);
需要注意的是,在Headers注解里,你可以传入多个Vlaue,源码里面是通过String数组接收的。
- Header
使用 @Header 注解动态更新请求头,匹配的参数必须提供给 @Header ,若参数值为 null ,这个头会 被省略,否则,会使用参数值的 toString 方法的返回值。
@GET("project")
Call<ProjectBean>getProject3(@Header("Authorization")String
authorization);
- Body
使用 @Body 注解,指定一个对象作为 request body 。在使用post请求的时候会被用到。
@POST("project/new")
Call<ProjectBean> createProject(@Body ProjectBean user);
- Field和FieldMap
@FormUrlEncoded
@POST("xxx")
fun exmaple4(@Field("name") vararg name:String,
@Field("array") array: Array<String>,//name=xxx&age=22
@FieldMap map: Map<String,String>
): Call<ResponseBody>
- Path
@GET("project/{id}/list")
fun exmaple5(@Path("id") id: Int): Call<ResponseBody>
- Query和QueryMap
//http://www.xxx.xxx?name=sss&age=22
@GET("xxxx")
fun search(@Query("name") name: String,
@QueryMap map: Map<String,String>): Call<ResponseBody>
Query和QueryMap是非常常用的,用于Get请求中指定参数
剩下的参数类注解都是用于表单字段的和Form表单请求一起讲。
3、 标志类注解
image.png- Streaming
例如我们服务端返回给我们的图片是以流的方法返回的,我们就可以用到Streaming注解,我这里写个伪代码给大家看看Streaming的使用。
@Streaming
@GET
Call<ProjectBean> downloadFile(@Url String fileUrl);
4、上传单个、多个文件
- 单个文件
//第一种方法:RequestBody
@Multipart
@POST("project/upload")
fun upload(@Part("file\";filename=\"test.png") file: RequestBody): Call<ResponseBody>
//上传单个文件
val file = File("")
val requestBody = RequestBody.create(MediaType.parse("image/png"),file)
val call = wanAndroidApi.upload(requestBody)
call.enqueue(object : Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
}
})
//第二种方法:MultipartBody.Part
@Multipart
@POST("project/upload")
fun upload2(@Part file: MultipartBody.Part): Call<RequestBody>
val file = File("")
val requestBody = RequestBody.create(MediaType.parse("image/png"),file)
val filePart = MultipartBody.Part.createFormData("上传的key",
file.name,requestBody)
val call = wanAndroidApi.upload2(filePart)
call.execute()//我这里为了演示,其实是要异步的
- 多个文件
//第一种方法:RequestBody
@Multipart
@POST("project/upload")
fun upload3(@PartMap map: Map<String,RequestBody>): Call<RequestBody>
//图片集合
val files = listOf<File>()
val map = mutableMapOf<String,RequestBody>()
files.forEach() {file ->
val requestBody = RequestBody.create(MediaType.parse("image/png"),file)
map["file\";filename=\"test.png"] = requestBody
}
wanAndroidApi.upload3(map)
//第二种方法:MultipartBody.Part
@Multipart
@POST("project/upload")
fun upload4(@PartMap map: Map<String,MultipartBody.Part>): Call<RequestBody>
val files = listOf<File>()
val map = mutableMapOf<String,MultipartBody.Part>()
files.forEachIndexed { index, file ->
val requestBody = RequestBody.create(MediaType.parse("image/png"),file)
val part = MultipartBody.Part.createFormData("上传的key${index}",file.name,requestBody)
map["上传的key${index}"] = part
}
wanAndroidApi.upload4(map)
网友评论