Retrofit是现在比较流行的网络请求框架,可以理解为okhttp的加强版,底层封装了Okhttp。
准确来说,Retrofit是一个RESTful的http网络请求框架的封装。因为网络请求工作本质上是由okhttp来完成,而Retrofit负责网络请求接口的封装。
https://square.github.io/retrofit/
添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
添加依赖
implementation ("com.squareup.retrofit2:retrofit:2.9.0")
implementation ("com.squareup.retrofit2:converter-gson:2.9.0")
Retrofit使用大量注解来简化请求,Retrofit将okhttp请求抽象成接口,使用注解来配置和描述网络请求参数。
请求方法注解 | 说明 |
---|---|
@GET | get请求 |
@POST | post请求 |
@PUT | put请求 |
@DELETE | delete请求 |
@PATCH | patch请求,该请求是对put请求的补充,用于更新局部资源 |
@HEAD | head请求 |
@OPTIONS | options请求 |
@HTTP | 通过注解,可以替换以上所有的注解,它拥有三个属性:method、path、hasBody |
请求头注解 | 说明 |
---|---|
@Headers | 用于添加固定请求头,可以同时添加多个,通过该注解的请求头不会相互覆盖,而是共同存在 |
@Header | 作为方法的参数传入,用于添加不固定的header,它会更新已有请求头 |
请求参数注解 | 说明 |
---|---|
@Body | 多用于Post请求发送非表达数据,根据转换方式将实例对象转化为对应字符串传递参数,比如使用Post发送Json数据,添加GsonConverterFactory则是将body转化为json字符串进行传递 |
@Filed | 多用于Post方式传递参数,需要结合@FromUrlEncoded使用,即以表单的形式传递参数 |
@FiledMap | 多用于Post请求中的表单字段,需要结合@FromUrlEncoded使用 |
@Part | 用于表单字段,Part和PartMap与@multipart注解结合使用,适合文件上传的情况 |
@PartMap | 用于表单字段,默认接受类型是Map<String,RequestBody>,可用于实现多文件上传 |
@Path | 用于Url中的占位符 |
@Query | 用于Get请求中的参数 |
@QueryMap | 与Query类似,用于不确定表单参数 |
@Url | 指定请求路径 |
标记类注解 | 说明 |
---|---|
@FormUrlEncoded | 表示请求发送编码表单数据,每个键值对需要使用@Filed注解 |
@Multipart | 表示请求发送form_encoded数据(使用于有文件上传的场景),每个键值对需要用@Part来注解键名,随后的对象需要提供值 |
@Streaming | 表示响应用字节流的形式返回,如果没有使用注解,默认会把数据全部载入到内存中,该注解在下载大文件时特别有用 |
@GET("user")
Call<ResponseBody> getData2(@Query("id") long idLon, @Query("name") String nameStr);
@GET("user")
Call<ResponseBody> getData3(@QueryMap Map<String, Object> map);
@FormUrlEncoded
@POST("user/emails")
Call<ResponseBody> getPostData2(@Field("name") String nameStr, @Field("sex") String sexStr);
@FormUrlEncoded
@POST("user/emails")
Call<ResponseBody> getPsotData3(@FieldMap Map<String, Object> map);
@POST("user/emails")
Call<ResponseBody> getPsotDataBody(@Body RequestBody body);
@GET("orgs/{id}")
Call<ResponseBody> getPathData(@Query("name") String nameStr, @Path("id") long idLon);
@Multipart
@POST("user/followers")
Call<ResponseBody> getPartData(@Part("name") RequestBody name, @Part MultipartBody.Part file);
调用
//声明类型,这里是文字类型
MediaType textType = MediaType.parse("text/plain");
//根据声明的类型创建RequestBody,就是转化为RequestBody对象
RequestBody name = RequestBody.create(textType, "这里是你需要写入的文本:刘亦菲");
//创建文件,这里演示图片上传
File file = new File("文件路径");
if (!file.exists()) {
file.mkdir();
}
//将文件转化为RequestBody对象
//需要在表单中进行文件上传时,就需要使用该格式:multipart/form-data
RequestBody imgBody = RequestBody.create(MediaType.parse("image/png"), file);
//将文件转化为MultipartBody.Part
//第一个参数:上传文件的key;第二个参数:文件名;第三个参数:RequestBody对象
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), imgBody);
Call<ResponseBody> partDataCall = retrofit.create(Api.class).getPartData(name, filePart);
@Multipart
@POST("user/followers")
Call<ResponseBody> getPartMapData(@PartMap Map<String, MultipartBody.Part> map);
调用
File file1 = new File("文件路径");
File file2 = new File("文件路径");
if (!file1.exists()) {
file1.mkdir();
}
if (!file2.exists()) {
file2.mkdir();
}
RequestBody requestBody1 = RequestBody.create(MediaType.parse("image/png"), file1);
RequestBody requestBody2 = RequestBody.create(MediaType.parse("image/png"), file2);
MultipartBody.Part filePart1 = MultipartBody.Part.createFormData("file1", file1.getName(), requestBody1);
MultipartBody.Part filePart2 = MultipartBody.Part.createFormData("file2", file2.getName(), requestBody2);
Map<String,MultipartBody.Part> mapPart = new HashMap<>();
mapPart.put("file1",filePart1);
mapPart.put("file2",filePart2);
Call<ResponseBody> partMapDataCall = retrofit.create(Api.class).getPartMapData(mapPart);
假如我们要请求
https://www.psvmc.cn/userlist.json
import java.util.List;
public class ResultListVo<T> {
private int code;
private String msg;
private List<T> obj;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public List<T> getObj() {
return obj;
}
public void setObj(List<T> obj) {
this.obj = obj;
}
}
用户
public class UserVo {
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface UserApi {
//get请求
@GET("userlist.json")
Call<ResultListVo<UserVo>> getUserList();
}
//构建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
//设置网络请求BaseUrl地址
.baseUrl("https://www.psvmc.cn/")
//设置数据解析器
.addConverterFactory(GsonConverterFactory.create())
.build();
//创建网络请求接口对象实例
UserApi userApi = mRetrofit.create(UserApi.class);
//对发送请求进行封装
Call<ResultListVo<UserVo>> resultCall = userApi.getUserList();
同步调用
//同步请求
Response<ResultListVo<UserVo>> data= resultCall.execute();
异步调用
//异步请求
resultCall.enqueue(new Callback<ResultListVo<UserVo>>() {
//请求成功回调
@Override
public void onResponse(Call<ResultListVo<UserVo>> call, Response<ResultListVo<UserVo>> response) {
ResultListVo<UserVo> body = response.body();
}
//请求失败回调
@Override
public void onFailure(Call<ResultListVo<UserVo>> call, Throwable t) {
}
});
新版本的Retrofit已经可以方便使用Kotlin的协程。
添加suspend关键字,返回类型Response<T>
import com.xhkjedu.xh_control_appstore.model.ResultListVo
import com.xhkjedu.xh_control_appstore.model.UserVo
import retrofit2.Response
import retrofit2.http.GET
interface UserApi {
//get请求
@GET("userlist.json")
suspend fun getUserList(): Response<ResultListVo<UserVo>>
}
GlobalScope.launch {
var result = ApiManager.userApi.getUserList().body()
Log.i("API", Gson().toJson(result))
}
BaseViewModel
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
open class BaseViewModel : ViewModel() {
var zIsShowMsg = mutableStateOf(false)
var zShowMsgContent = mutableStateOf("")
fun mLaunch(block: suspend () -> Unit) {
viewModelScope.launch(Dispatchers.IO) {
try {
block()
} catch (e: Exception) {
withContext(Dispatchers.Main){
zIsShowMsg.value = true
zShowMsgContent.value = "接口请求失败"
}
}
}
}
}
UserViewModel
import android.util.Log
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import com.google.gson.Gson
import com.xhkjedu.xh_control_appstore.api.ApiManager
import com.xhkjedu.xh_control_appstore.model.UserVo
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class UserViewModel : BaseViewModel() {
val userList = mutableStateListOf<UserVo>()
fun loadData() {
mLaunch {
Log.i("API2", Thread.currentThread().name)
val result = ApiManager.userApi.getUserList().body()
withContext(Dispatchers.Main) {
result?.let {
if (result.code == 0) {
userList.addAll(result.obj)
zIsShowMsg.value = false
} else {
zIsShowMsg.value = true
zShowMsgContent.value = result.msg
}
}
}
}
}
}
查看