Retrofit
2020-01-15 本文已影响0人
Liu积土成山
Retrofit用法总结
一.什么是retrofit
retrofit是现在比较流行的网络请求框架,可以理解为okhttp的加强版,底层封装了Okhttp。准确来说,Retrofit是一个RESTful的http网络请求框架的封装。因为网络请求工作本质上是由okhttp来完成,而Retrofit负责网络请求接口的封装。
本质过程:App应用程序通过Retrofit请求网络,实质上是使用Retrofit接口层封装请求参数、Header、Url等信息,之后由okhttp来完成后续的请求工作。在服务端返回数据后,okhttp将原始数据交给Retrofit,Retrofit根据用户需求解析。
retrofit优点
超级解耦 ,接口定义、接口参数、接口回调不在耦合在一起
可以配置不同的httpClient来实现网络请求,如okhttp、httpclient
支持同步、异步、Rxjava
可以配置不同反序列化工具类来解析不同的数据,如json、xml
请求速度快,使用方便灵活简洁
一.引入依赖
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
1、请求方法注解
请求方法注解 | 说明 |
---|---|
@GET | Get请求 |
@POST | post请求 |
@PUT | put请求 |
@DELETE | delete请求 |
@PATCH | patch请求,该请求是对put请求的补充,用于更新局部资源 |
@HEAD | head请求 |
@HEAD | options请求 |
2、请求头注解
请求头注解 | 说明 |
---|---|
@Headers | 用于添加固定请求头,可以同时添加多个,通过该注解的请求头不会相互覆盖,而是共同存在 |
@Header | 作为方法的参数传入,用于添加不固定的header,它会更新已有请求头 |
3、请求参数注解
请求参数注解 | 说明 |
---|---|
@Body | 多用于Post请求发送非表达数据,根据转换方式将实例对象转化为对应字符串传递参数,比如使用Post发送Json数据 |
@Filed | 多用于Post方式传递参数,需要结合@FromUrlEncoded使用,即以表单的形式传递参数 |
@FiledMap | 多用于Post请求中的表单字段,需要结合@FromUrlEncoded使用 |
@Part | 用于表单字段,Part和PartMap与@multipart注解结合使用,适合文件上传的情况 |
@PartMap | 用于表单字段,默认接受类型是Map<String,RequestBody>,可用于实现多文件上传 |
@Path | 用于Url中的占位符 |
@Query | 用于Get请求中的参数 |
@QueryMap | 与Query类似,用于不确定表单参数 |
@Url | 指定请求路径 |
4、请求和响应格式(标记)注解
标记类注解 | 说明 |
---|---|
@FromUrlCoded | 表示请求发送编码表单数据,每个键值对需要使用@Filed注解 |
@Multipart | 表示请求发送form_encoded数据(使用于有文件上传的场景),每个键值对需要用@Part来注解键名,随后的对象需要提供值 |
@Streaming | 表示响应用字节流的形式返回,如果没有使用注解,默认会把数据全部载入到内存中,该注解在下载大文件时特别有用 |
1.0
首先创建我们的接口
public interface API {
/**
* @GET方法 请求方法注解,get请求,括号内的是请求地址,Url的一部分
* Call<*> 返回类型,*表示接收数据的类,一般自定义
* getJson 接口方法名称,括号内可以写入参数
* 这是一个没有网络参数的get请求方式,需要在方法头部添加@GET注解,表示采用get方法访问网络请求,括号
* 内的是请求的地址(Url的一部分) ,其中返回类型是Call<*>,*表示接收数据的类,如果想直接获取ResponseBody中的内容,可以定义网络请求返回值为Call<ResponseBody>,ResponseBody是请求网络后返回
* 的原始数据,如果网络请求没有参数,不用写。因为我这里用postman进行了测试知道返回的具体内容是什么了,
*所以我创建了个javaBean,名字叫JsonResultBean,如果不知道想看返回的原始数据则使用*Call<ResponseBody> getJson();
*/
@GET("get/text")
Call<JsonResultBean> getJson();
// 带参数的,如果是参数少可以用@Query请求参数注解
// "keyword" 参数字段,与后台给的参数保持一致
// String 声明参数的类型
@GET("/get/param")
Call<GetWithParamsBean> getWithParams(@Query("keyword") String keyword,
@Query("page") int page,
@Query("order") String order);
// 如果参数多可以用QueryMap,请求参数注解,与@Query类似,用于不确定表单参数
// Map<String, Object> params 通过Map将不确定的参数传入,相当于多个Query参数
@GET("/get/param")
Call<GetWithParamsBean> getWithParams(@QueryMap Map<String,Object> params);
// post
@POST("/post/string")
Call<PostWithParamsBean> postWithParams(@Query("string") String content);
// 没有参数的post方法 @POST请求方法注解,表示采用post方法访问网络请求,括号后面是部分的URL地址
@POST
Call<PostWithParamsBean> postWithUrl(@Url String url);
// post上传表单
// @FormUrlEncoded 请求格式注解,请求实体是一个From表单,每个键值对需要使用@Field注解
// @Field 请求参数注解,提交请求的表单字段,必须要添加,而且需要配合@FormUrlEncoded使用
// "userName" 参数字段,与后台必须保持一致
// userName password 传进来实际的参数
//Post请求如果有参数需要在头部添加@FormUrlEncoded注解,表示请求实体是一个From表单,每个键值对
//需要使用@Field注解,使用@Field添加参数,这是发送Post请求时,提交请求的表单字段,必须要添加的,
//而且需要配合@FormUrlEncoded使用
@FormUrlEncoded
@POST("/login")
Call<ResponseBody> doLogin(@Field("userName") String userName, @Field("password") String password);
// post 参数多的时候传递,@FieldMap 请求参数注解,与@Field作用一致,用于不确定表单参数
// Map<String, Object> map 通过Map将不确定的参数传入,相当于多个Field参数
@FormUrlEncoded
@POST("/login")
Call<ResponseBody> postLoginMap(@FieldMap Map<String,Object> params);
// postJsonObject 传递对象
@POST("/post/comment")
Call<PostWithJsonObjectBean> postJsonObjet(@Body CommentItemBean itemBean);
// 上传文件,文件可以包括 图片 、 视频、音频 @Part注解,要跟@Multipart注解一起使用
// 我们可以在方法参数内添加请求头,@Header用于添加不固定的请求头,作用于方法的参数,作为方法的
// 参数传入,该注解会更新已有的请求头。header用于添加不固定的请求头,headers用于添加固定的请求头
// @Multipart 表示请求实体是一个支持文件上传的表单,需要配合@Part和@PartMap使用,适用于文件上传
// 用于表单字段,适用于文件上传的情况,@Part支持三种类型:RequestBody、MultipartBody.Part、 任意
// 类型
// @PartMap用于多文件上传, 与@FieldMap和@QueryMap的使用类似
@Multipart
@POST("/api/AppAniImgType/UploadToAliyun")
Call<FileUploadResult> postFile(@HeaderMap Map<String,Object> headers,@Part MultipartBody.Part file);
}
/**
* 多文件上传:通过 List<MultipartBody.Part> 传入多个part实现
* @param parts 每一个part代表一个文件
* @return 状态信息String
*/
@Multipart
@POST("UploadServerAddr")
Call<String> uploadFilesMultipartBodyParts(@Part() List<MultipartBody.Part> parts);
// @Streaming表示响应体的数据用流的方式返回,使用于返回数据比较大,该注解在下载大文件时特别有用
@Streaming
@POST("gists/public")
Call<ResponseBody> getStreamingBig();
1.1
新建一个单例功我们所有页面使用的网络请求-包含我们的baseUrl
public class RetrofitManager {
// 我们的baseUrl
public static String BASE_URL="http://xxxxx/";
//设置超时时间
public static final int CONNECT_TIME_OUT = 100000;
private static RetrofitManager sRetrofitManager = null;
private Retrofit mRetrofit;
private RetrofitManager() {
createRetrofit();
}
private void createRetrofit() {
//设置一下okHttp的参数
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS)
.build();
mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())// 转换器直接转换成了bean类
.build();
}
public static RetrofitManager getInstance() {
if (sRetrofitManager == null) {
synchronized (RetrofitManager.class) {
if (sRetrofitManager == null) {
sRetrofitManager = new RetrofitManager();
}
}
}
return sRetrofitManager;
}
public Retrofit getRetrofit() {
return mRetrofit;
}
}
二. 在我们的页面中使用
private API mApi;
在onCreate()方法中调用
mApi = RetrofitManager.getInstance().getRetrofit().create(API.class);
/*
* get方法请求网路
* */
public void getClickRequest(View view) {
Call<JsonResultBean> task = mApi.getJson();
task.enqueue(new Callback<JsonResultBean>() {
@Override
public void onResponse(Call<JsonResultBean> call, Response<JsonResultBean> response) {
Log.i(TAG, "onResponse:----> " + response.code());
if (response.code() == HttpURLConnection.HTTP_OK) {
JsonResultBean resultBean = response.body();
updateList(resultBean);
}
}
@Override
public void onFailure(Call<JsonResultBean> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/**
* 带参数的请求
*/
public void getClickParams(View view) {
Call<GetWithParamsBean> task = mApi.getWithParams("大家好", 10, "10");
task.enqueue(new Callback<GetWithParamsBean>() {
@Override
public void onResponse(Call<GetWithParamsBean> call, Response<GetWithParamsBean> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (response.code() == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<GetWithParamsBean> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/**
* 带参数的用QueryMap
*/
public void getClickParamsQueryMap(View view) {
Map<String, Object> params = new HashMap<>();
params.put("keyword", "搜索关键字");
params.put("page", 10);
params.put("order", "0");
Call<GetWithParamsBean> task = mApi.getWithParams(params);
task.enqueue(new Callback<GetWithParamsBean>() {
@Override
public void onResponse(Call<GetWithParamsBean> call, Response<GetWithParamsBean> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (response.code() == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<GetWithParamsBean> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/**
* post
*/
public void postClickParamsQuery(View view) {
Call<PostWithParamsBean> task = mApi.postWithParams("测试内容");
task.enqueue(new Callback<PostWithParamsBean>() {
@Override
public void onResponse(Call<PostWithParamsBean> call, Response<PostWithParamsBean> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (response.code() == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<PostWithParamsBean> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/*
* postUrl
* */
public void postWithUrl(View view) {
// 参数是 string
String url = "/post/string?string=测试内容";
Call<PostWithParamsBean> task = mApi.postWithUrl(url);
task.enqueue(new Callback<PostWithParamsBean>() {
@Override
public void onResponse(Call<PostWithParamsBean> call, Response<PostWithParamsBean> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (response.code() == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<PostWithParamsBean> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/*
* post请求,body携带字符串内容(json)
* */
public void postJsonObject(View view) {
CommentItemBean itemBean = new CommentItemBean();
itemBean.setArticleId("123456");
itemBean.setCommentContent("这是我提交测试的评论内容...");
// PostWithJsonObjectBean 也可以通过对象形式拿返回值
Call<PostWithJsonObjectBean> task = mApi.postJsonObjet(itemBean);
task.enqueue(new Callback<PostWithJsonObjectBean>() {
@Override
public void onResponse(Call<PostWithJsonObjectBean> call, Response<PostWithJsonObjectBean> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (code == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<PostWithJsonObjectBean> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/*
* 拦截器的使用
* */
public void postJsonObject2(View view) {
CommentItemBean itemBean = new CommentItemBean();
itemBean.setArticleId("123456");
itemBean.setCommentContent("这是我提交测试...");
OkHttpClient.Builder okhttpClient = new OkHttpClient.Builder();
HttpLoggingInterceptor looger = new HttpLoggingInterceptor();
looger.setLevel(HttpLoggingInterceptor.Level.BODY);
// 只在开发版本中才会记录
if (BuildConfig.DEBUG) {
okhttpClient.addInterceptor(looger);
}
okhttpClient.addInterceptor(looger);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RetrofitManager.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())// 转换器直接转换成了bean类
.client(okhttpClient.build())
.build();
API service = retrofit.create(API.class);
Call<PostWithJsonObjectBean> call = service.postJsonObjet(itemBean);
call.enqueue(new Callback<PostWithJsonObjectBean>() {
@Override
public void onResponse(Call<PostWithJsonObjectBean> call, Response<PostWithJsonObjectBean> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (code == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<PostWithJsonObjectBean> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/*
* 登录 提交表单
* */
public void clickLogin(View view) {
Call<ResponseBody> call = mApi.doLogin("admin","123456");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,Response<ResponseBody> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (code == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/*
* 提交表单 map 多参数形式
* */
public void postLoginMap(View view){
HashMap<String,Object> map = new HashMap<>();
map.put("admin","张三");
map.put("password","123456");
Call<ResponseBody> call = mApi.postLoginMap(map);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (code == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/*
* post file 上传文件 文件包括 图片 视频 音频等等
* @Part注解,要跟@Multipart注解一起使用。
* */
public void postFile(View view) {
// String path = Environment.getExternalStorageDirectory() + File.separator + "20191220_113301.jpg";
//创建文件,这里演示图片上传
File file = new File("/storage/emulated/0/Download/1.jpg");
if (!file.exists()) {
file.mkdir();
}
//声明类型,这里是传的图片
MediaType mediaType = MediaType.parse("image/*");
//将文件转化为RequestBody对象
//需要在表单中进行文件上传时,就需要使用该格式:multipart/form-data
RequestBody fileBody = RequestBody.create(mediaType, file);
// MultipartBody.Part 和后端约定好Key,这里的partName是用file
// 将文件转化为MultipartBody.Part
//第一个参数:上传文件的key;第二个参数:文件名;第三个参数:RequestBody对象
MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), fileBody);
// 添加描述
// String descriptionString = "hello, 这是文件描述";
// RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("authToken", "08c958df-187f-4e11-973b-3495a8e8e0ae");
hashMap.put("appKey", "6f9f7cfd-a92d-45a0-8e4a-d2aa96b84b27");
Call<FileUploadResult> task = mApi.postFile(hashMap, part);
task.enqueue(new Callback<FileUploadResult>() {
@Override
public void onResponse(Call<FileUploadResult> call, Response<FileUploadResult> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (code == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<FileUploadResult> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}
/*
* 多文件上传
* */
public void partMapDataCall(View view) {
ArrayList<File> list = new ArrayList<>();
list.add(new File("/sdcard/0/test0.jpg"));
list.add(new File("/sdcard/0/test1.jpg"));
List<MultipartBody.Part> parts = new ArrayList<>(list.size());
for(File file : list) {
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("image", file.getName(), requestBody);
parts.add(part);
}
Call<String> call = mApi.uploadFilesMultipartBodyParts(parts);
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
int code = response.code();
Log.i(TAG, "onResponse:----> " + code);
if (code == HttpURLConnection.HTTP_OK) {
Log.i(TAG, "onResponse:---->" + response.body());
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
Log.i(TAG, "onFailure: ---->" + t.toString());
}
});
}