一.简介
Retrofit是Square 公司开发的一款正对Android 网络请求的框架。底层基于OkHttp 实现。
Retrofit官网地址:Retrofit
RetrofitGItHub地址GitHub - square/retrofit: A type-safe HTTP client for Android and the JVM
二.注解详解
Retrofit的一大特点就是注解,下面讲解常用的注解
1.和请求方法相关的注解
<1> get
@GET("openapi.dokeyfrom=imoocdict123456&key=324273592&type=data&doctype=json&version=1.1&q=blue")
Call<ResponseBody> getFanYiData();
<2> post
@FormUrlEncoded
@POST("openapi.do")
Call<ResponseBody> login(@Field("keyfrom") String param1, @Field("key") String params2, @Field("type") String param3, @Field("doctype") String param4, @Field("version") String param5, @Field("q") String param6);
<3> head
<4> put
<5> delete
<6> patch
2.和参数相关的注解
<1> Path
用于替换请求地址,作用于方法参数。
@GET("{public}")
Call<BaseResult<List<User>>> getUser(@Path("public") String path);
<2> Field
用于表单字段参数,(需要配合FormUrlEncoded使用)作用于方法参数。
@FormUrlEncoded
@POST("public")
Call<BaseResult> addUser(@Field("userName") String userName);
<3> Multipart
指请求体是一个支持文件上传的Form表单,Content-Type=multipart/form-data,需要和参数类注解@Part,@PartMap搭配使用。
@Multipart
@POST("public")
Call<BaseResult> uploadFile(@Part MultipartBody.Part file);
@Multipart
@POST("users/image")
Call<BaseResponse<String>> uploadFilesWithParts(@Part() List<MultipartBody.Part> parts);
@POST("users/image")
Call<BaseResponse<String>> uploadFileWithRequestBody(@Body MultipartBody multipartBody);
注意:
使用@Multipart注解方法,并用@Part注解方法参数,类型是List< okhttp3.MultipartBody.Part>。
不使用@Multipart注解方法,直接使用@Body注解方法参数,类型是okhttp3.MultipartBody。
<4> FormUrlEncoded
指请求体是一个Form表单,Content-Type=application/x-www-form-urlencoded,需要和参数类注解@Field,@FieldMap搭配使用。
@FormUrlEncoded
@POST("login")
Flowable<HttpResult<UserInfoData>> login(@FieldMap Map<String, String> map);
@FormUrlEncoded
@POST("public")
Call<BaseResult> addUser(@Field("userName") String userName);
<5> Streaming
指响应体的数据以流的形式返回,如果不使用默认会把数据全部加载到内存,所以下载文件时需要加上这个注解。
@Streaming
@GET("download")
Call<ResponseBody> downloadFile();
<6> FieldMap
用于表单字段参数,接收Map实现多个参数,(需要配合FormUrlEncoded使用)作用于方法参数。
@FormUrlEncoded
@POST("public")
Call<BaseResult> addUser(@FieldMap Map<String,String> fieldMap);
<7> Part
用于表单字段参数,适用于文件上传,(需要配合Multipart使用)作用于方法参数。
@Multipart
@POST("public")
Call<BaseResult> uploadFile(@Part MultipartBody.Part file);
<8> PartMap
用于表单字段参数,适用于文件上传,(需要配合Multipart使用)作用于方法参数。
@Multipart
@POST("public")
Call<BaseResult> uploadFile(@PartMap Map<String,RequestBody> RequestBodyMap);
<9> Query
用于条件字段参数,作用于方法参数(主要在GET中使用)。
@GET("public")
Call<BaseResult<List<User>>> getUser(@Query("userId") String userId);
<10> QueryMap
用于条件字段参数,作用于方法参数(主要在GET中使用)。
@GET("public")
Call<BaseResult<List<User>>> getUser(@QueryMap Map<String,String> map);
<11> Body
作用于方法参数。
@POST("public")
Call<BaseResult<List<User>>> getUser(@Body( User user);
注意:
<1> 使用Post请求方式
(1) 表单提交:建议使用Field或FieldMap+FormUrlEncoded,以键值对上传到服务器。
(2) JSON提交:建议使用@Body,大部分都是实体类,最后将实体类转换为JSON,上传服务器。
<2> 使用GET请求方式
(1) 建议使用Query或QueryMap都是将参数拼接在url后面的。
三.代码实现
1.Gradle依赖
implementation 'com.squareup.retrofit2:retrofit:2.7.0'
2.接口
package com.wjn.rxdemo.retrofit.only;
import java.util.Map;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
/**
* 翻译接口
*/
public interface FanYiService {
/**
* 翻译模块Get请求
*/
@GET("openapi.do?keyfrom=imoocdict123456&key=324273592&type=data&doctype=json&version=1.1&q=blue")
Call<ResponseBody> getFanYiByGet();
/**
* 翻译模块Post请求 Field方式 单个参数逐一传参
*/
@FormUrlEncoded
@POST("openapi.do")
Call<ResponseBody> getFanYiByPost(@Field("keyfrom") String param1, @Field("key") String params2, @Field("type") String param3, @Field("doctype") String param4, @Field("version") String param5, @Field("q") String param6);
/**
* 翻译模块Post请求 FieldMap 集合传参
*/
@FormUrlEncoded
@POST("openapi.do")
Call<ResponseBody> getFanYiByPost(@FieldMap Map<String, String> map);
}
3.测试页面
package com.wjn.networkdemo.retrofit.only;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.wjn.networkdemo.R;
import java.io.IOException;
import java.util.HashMap;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class RetrofitActivity extends AppCompatActivity {
private Retrofit mRetrofit;
private FanYiService mFanYiService;
private String mBaseUrl = "http://fanyi.youdao.com/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_retrofit);
//获取Retrofit对象
mRetrofit = new Retrofit.Builder()
.baseUrl(mBaseUrl)//设置BaseUrl 必须以'/'结尾
.build();
//Get请求
findViewById(R.id.activity_retrofit_textview1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getData();
}
});
//Post请求 单一参数
findViewById(R.id.activity_retrofit_textview2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
postData();
}
});
//Post请求 集合参数
findViewById(R.id.activity_retrofit_textview3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
postMapData();
}
});
}
/**
* Retrofit Get请求
*/
private void getData() {
if (null != mRetrofit) {
mFanYiService = mRetrofit.create(FanYiService.class);
Call<ResponseBody> getCall = mFanYiService.getFanYiByGet();
getCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (null == call || null == response) return;
//参数call信息打印
boolean canceled = call.isCanceled();
Request request = call.request();
HttpUrl url = request.url();
String method = request.method();
Log.d("RetrofitActivity", "Get请求onResponse方法canceled----:" + canceled);
Log.d("RetrofitActivity", "Get请求onResponse方法url.toString()----:" + url.toString());
Log.d("RetrofitActivity", "Get请求onResponse方法method----:" + method);
//参数response信息打印
String result = null;//报文 获取报文必须判断响应是否成功
if (response.isSuccessful()) {
try {
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
String msg = response.toString();
int code = response.code();
boolean isSuccess = response.isSuccessful();
Log.d("RetrofitActivity", "Get请求onResponse方法result----:" + result);
Log.d("RetrofitActivity", "Get请求onResponse方法msg----:" + msg);
Log.d("RetrofitActivity", "Get请求onResponse方法code----:" + code);
Log.d("RetrofitActivity", "Get请求onResponse方法isSuccess----:" + isSuccess);
} else {
Log.d("RetrofitActivity", "Get请求onResponse方法isSuccess----:" + false);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("RetrofitActivity", "Get请求onFailure方法result2----:" + t.getMessage());
}
});
}
}
/**
* Retrofit Post请求 单一参数
*/
private void postData() {
if (null != mRetrofit) {
mFanYiService = mRetrofit.create(FanYiService.class);
Call<ResponseBody> postCall = mFanYiService.getFanYiByPost("imoocdict123456", "324273592", "data", "json", "1.1", "red");
postCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (null == call || null == response) return;
//参数call信息打印
boolean canceled = call.isCanceled();
Request request = call.request();
HttpUrl url = request.url();
String method = request.method();
Log.d("RetrofitActivity", "Post请求onResponse方法canceled----:" + canceled);
Log.d("RetrofitActivity", "Post请求onResponse方法url.toString()----:" + url.toString());
Log.d("RetrofitActivity", "Post请求onResponse方法method----:" + method);
//参数response信息打印
String result = null;//报文 获取报文必须判断响应是否成功
if (response.isSuccessful()) {
try {
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
String msg = response.toString();
int code = response.code();
boolean isSuccess = response.isSuccessful();
Log.d("RetrofitActivity", "Post请求onResponse方法result----:" + result);
Log.d("RetrofitActivity", "Post请求onResponse方法msg----:" + msg);
Log.d("RetrofitActivity", "Post请求onResponse方法code----:" + code);
Log.d("RetrofitActivity", "Post请求onResponse方法isSuccess----:" + isSuccess);
} else {
Log.d("RetrofitActivity", "Post请求onResponse方法isSuccess----:" + false);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("RetrofitActivity", "Post请求onFailure方法result2----:" + t.getMessage());
}
});
}
}
/**
* Retrofit Post请求 集合参数
*/
private void postMapData() {
if (null != mRetrofit) {
mFanYiService = mRetrofit.create(FanYiService.class);
HashMap<String, String> map = new HashMap<>();
map.put("keyfrom", "imoocdict123456");
map.put("key", "324273592");
map.put("type", "data");
map.put("doctype", "json");
map.put("version", "1.1");
map.put("q", "red");
Call<ResponseBody> postCall = mFanYiService.getFanYiByPost(map);
postCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (null == call || null == response) return;
//参数call信息打印
boolean canceled = call.isCanceled();
Request request = call.request();
HttpUrl url = request.url();
String method = request.method();
Log.d("RetrofitActivity", "Post Map 请求onResponse方法canceled----:" + canceled);
Log.d("RetrofitActivity", "Post Map 请求onResponse方法url.toString()----:" + url.toString());
Log.d("RetrofitActivity", "Post Map 请求onResponse方法method----:" + method);
//参数response信息打印
String result = null;//报文 获取报文必须判断响应是否成功
if (response.isSuccessful()) {
try {
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
String msg = response.toString();
int code = response.code();
boolean isSuccess = response.isSuccessful();
Log.d("RetrofitActivity", "Post Map 请求onResponse方法result----:" + result);
Log.d("RetrofitActivity", "Post Map 请求onResponse方法msg----:" + msg);
Log.d("RetrofitActivity", "Post Map 请求onResponse方法code----:" + code);
Log.d("RetrofitActivity", "Post Map 请求onResponse方法isSuccess----:" + isSuccess);
} else {
Log.d("RetrofitActivity", "Post Map 请求onResponse方法isSuccess----:" + false);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("RetrofitActivity", "Post Map 请求onFailure方法result2----:" + t.getMessage());
}
});
}
}
}
4.结果
<1> Get请求
D/RetrofitActivity: Get请求onResponse方法canceled----:false
D/RetrofitActivity: Get请求onResponse方法url.toString()----:http://fanyi.youdao.com/openapi.do?keyfrom=imoocdict123456&key=324273592&type=data&doctype=json&version=1.1&q=blue
D/RetrofitActivity: Get请求onResponse方法method----:GET
D/RetrofitActivity: Get请求onResponse方法result----:{"translation":["蓝色的"],"basic":{"us-phonetic":"bluː","phonetic":"bluː","uk-phonetic":"bluː","explains":["adj. 蓝色的;忧郁的,悲观的;(由于冷或呼吸困难)发青的,青紫的;(电影、玩笑或故事)色情的,黄色的;(肉)未熟的;(政治上)保守的","n. 蓝色;蓝色物品;(牛津或剑桥大学的运动员)蓝色荣誉者;失误;红发人;打架","vt. (使)变成蓝色;把......染成蓝色;给\u2026\u2026上蓝色漂白剂;挥霍(钱财)","n. (Blue) (英、美、加、澳、新)布卢(人名)"]},"query":"blue","errorCode":0,"web":[{"value":["蓝色的","刀枪不入","蓝色橙味糖浆"],"key":"blue"},{"value":["蓝月","蓝月亮","千载难逢的时机"],"key":"Blue Moon"},{"value":["青尼罗省","青尼罗河","蓝色尼罗河"],"key":"Blue Nile"}]}
D/RetrofitActivity: Get请求onResponse方法msg----:Response{protocol=http/1.1, code=200, message=OK, url=http://fanyi.youdao.com/openapi.do?keyfrom=imoocdict123456&key=324273592&type=data&doctype=json&version=1.1&q=blue}
D/RetrofitActivity: Get请求onResponse方法code----:200
D/RetrofitActivity: Get请求onResponse方法isSuccess----:true
<2> Post请求 单个参数逐一传参
D/RetrofitActivity: Post请求onResponse方法canceled----:false
D/RetrofitActivity: Post请求onResponse方法url.toString()----:http://fanyi.youdao.com/openapi.do
D/RetrofitActivity: Post请求onResponse方法method----:POST
D/RetrofitActivity: Post请求onResponse方法result----:{"translation":["红色的"],"basic":{"us-phonetic":"red","phonetic":"red","uk-phonetic":"red","explains":["adj. 红的,红色的;(毛发)红褐色的;(脸)涨红的;(眼睛)红肿的;革命的,激进的;(人)红种的;(纸牌中)红桃的,红方块的;(葡萄酒)红的;(表示停止)红(灯),红(旗);被禁止的,危险的;(滑雪道上用红色标志指示)第二高难度的;(物理)表示夸克三种颜色之一的红色;赤色的(尤指冷战期间用于指前苏联);沾有鲜血的;(古或诗\/文)流血的;(科萨人)来自传统部落文化的","n. 红色,红颜料;红衣;红葡萄酒;红色物(或人);赤字,亏空;激进分子","n. (Red) 雷德(人名)"]},"query":"red","errorCode":0,"web":[{"value":["红","红色","赤焰战场"],"key":"RED"},{"value":["红线","台北捷运红线","红线机油"],"key":"Red Line"},{"value":["红旗","红旗演习","危险信号"],"key":"red flag"}]}
D/RetrofitActivity: Post请求onResponse方法msg----:Response{protocol=http/1.1, code=200, message=OK, url=http://fanyi.youdao.com/openapi.do}
D/RetrofitActivity: Post请求onResponse方法code----:200
D/RetrofitActivity: Post请求onResponse方法isSuccess----:true
<3> 集合方式传参
D/RetrofitActivity: Post Map 请求onResponse方法canceled----:false
D/RetrofitActivity: Post Map 请求onResponse方法url.toString()----:http://fanyi.youdao.com/openapi.do
D/RetrofitActivity: Post Map 请求onResponse方法method----:POST
D/RetrofitActivity: Post Map 请求onResponse方法result----:{"translation":["红色的"],"basic":{"us-phonetic":"red","phonetic":"red","uk-phonetic":"red","explains":["adj. 红的,红色的;(毛发)红褐色的;(脸)涨红的;(眼睛)红肿的;革命的,激进的;(人)红种的;(纸牌中)红桃的,红方块的;(葡萄酒)红的;(表示停止)红(灯),红(旗);被禁止的,危险的;(滑雪道上用红色标志指示)第二高难度的;(物理)表示夸克三种颜色之一的红色;赤色的(尤指冷战期间用于指前苏联);沾有鲜血的;(古或诗\/文)流血的;(科萨人)来自传统部落文化的","n. 红色,红颜料;红衣;红葡萄酒;红色物(或人);赤字,亏空;激进分子","n. (Red) 雷德(人名)"]},"query":"red","errorCode":0,"web":[{"value":["红","红色","赤焰战场"],"key":"RED"},{"value":["红线","台北捷运红线","红线机油"],"key":"Red Line"},{"value":["红旗","红旗演习","危险信号"],"key":"red flag"}]}
D/RetrofitActivity: Post Map 请求onResponse方法msg----:Response{protocol=http/1.1, code=200, message=OK, url=http://fanyi.youdao.com/openapi.do}
D/RetrofitActivity: Post Map 请求onResponse方法code----:200
D/RetrofitActivity: Post Map 请求onResponse方法isSuccess----:true
5.总结
<1> Retrofit的BaseUrl必须以"/"结尾
<2> Retrofit的Post请求须加注释
<3> Call方法发起请求可以用两种方式。一种enqueue异步 一种execute()同步。大多数请求会用异步。
<4> onResponse回调(即请求成功的回调)中,除了可以拿到请求的报文,还可以拿到很多其他的信息,比如请求码200,比如请求方法,比如请求Url等等。都是很有用的信息。且 获取报文必须判断响应是否成功。
<5> 单独使用Retrofit时,如果不配置CONVERTERS 即合成器 (详解见官网) 报文格式只能是 ResponseBody。