三三要成为安卓糕手
一:OkHttp介绍
OkHttp 是一个开源的、强大且高效的 HTTP 客户端库,主要用于在 Java后端和Android 项目中进行网络请求。
//在gradle中添加依赖
com.squareup.okhttp3:okhttp:4.12.0
二:GET请求
/**
* 使用OkHttp发起get请求
*/
private void sendGetRequest(){
String id = etUserId.getText().toString();
String urlAddress = "http://titok.fzqq.fun/addons/cms/api.user/userInfo?user_id=" + id + "&type=archives";
//创建OkHttpClient实例对象,用于发起请求
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
//设置请求属性,比如地址,方法属性
Request request = new Request.Builder()
.url(urlAddress)
.get()
.build();
//发起单个请求
Call call = okHttpClient.newCall(request);
//接收响应
Callback callback = new Callback() {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(response.isSuccessful()){
//响应成功
try {
String result = response.body().string();
Log.i(TAG, "run: result" + result);
//把json字符串转化为对象
UserInfoQuery userInfoQuery = new Gson().fromJson(result, UserInfoQuery.class);
String msg = "当前的用户名是:" + userInfoQuery.getData().getUser().getNickname();
Toast.makeText(OkHttpActivity.this,msg,Toast.LENGTH_SHORT).show();
} catch (IOException e) {
throw new RuntimeException(e);
}
}else{
Toast.makeText(OkHttpActivity.this,"网络请求失败"+response.code()
,Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OkHttpActivity.this,"网络请求失败",Toast.LENGTH_SHORT).show();
}
});
}
};
call.enqueue(callback);
}
1:大致步骤
- 使用builder去创建OkHttpClient实例对象,设置一些连接的属性:常见连接超时,数据读取超时
- 使用builder设置请求属性:常见url,get方法
- 调用newCall发起单次请求,传入request参数,使用enqueue异步线程
- new Callback();重写接口中的onResponse方法和onFailure方法
- 方法中的内部逻辑,对于ui的处理要在主线程中进行,调用runOnUiThread(new Runnable接口,重写run方法)
2:一些细节
- 我们一般不会直接new一个request,而是选择一个底下的一个builder的东西
(1)内部回调接口
在 OkHttp 中,call.enqueue(callback)
并非 “把响应丢进 call 里”,而是通过回调机制实现异步请求的结果处理
Call
对象是对一个 HTTP 请求的封装,调用enqueue(callback)
时,其实是向Call 注册了一个回调接口。- OkHttp 会在后台线程执行网络请求,当请求完成(成功或失败)后,会自动调用
onResponse
或onFailure
方法,并将响应结果(Response
对象)作为参数传入。
(2)次线程转主线程
接口中重写的onResponse方法和onFailure方法内部的代码,涉及到UI应该要回到主线程中去进行
回到主线程去完成ui(弹窗操作)
(3)enqueue方法的说明
“enqueue” 把…… 加入队列
在 Java 中,enqueue
方法的签名是 void enqueue(Callback responseCallback)
,它接收一个 Callback
类型的参数,Callback
是 OkHttp 中定义的一个接口,包含两个抽象方法:
onResponse(Call call, Response response)
:当 HTTP 请求成功完成,且服务器返回了响应时,该方法会被调用,response
参数包含了从服务器获取到的响应信息,比如响应码、响应头、响应体等;call
参数则是当前正在处理结果的这个请求对应的Call
对象。onFailure(Call call, IOException e)
:当请求执行过程中发生错误,比如网络连接失败、超时等情况,这个方法会被调用。
(4)response.body().string()
主要作用是将 ResponseBody
的内容以字符串形式读取出来。
它会根据响应体的编码(Content-Type
),把响应体中的字节数据解码为字符串。并非用toString方法
(5)toString () 方法
默认的 toString()
方法返回的是 ResponseBody
类的名称以及对象的哈希码等信息,而不是响应体中的实际内容。
例如:可能返回类似 okhttp3.ResponseBody@12345678
这样的字符串,其中 okhttp3.ResponseBody
是类名,@12345678
是对象的哈希码表示 。
(6)TimeUnit 时间单位
在设置超时方面,可以用安卓内部定义好的时间的单位常量
3:效果
三:POST请求
/**
* POST请求
*/
private void sendPostRequest(){
String loginUrl = "http://titok.fzqq.fun/addons/cms/api.login/login";
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10,TimeUnit.SECONDS)
.readTimeout(30,TimeUnit.SECONDS)
.build();
String account = etUserName.getText().toString();
String password = etPassword.getText().toString();
//用Gson去拼接一个请求体
String jsonBody = new Gson().toJson(new ReqLogin(account, password));
//请求体的数据格式是Json,编码格式是utf-8
MediaType mediaType = MediaType.get("application/json;charset=utf-8");
RequestBody requestBody = RequestBody.create(jsonBody, mediaType);
//构建请求
Request request = new Request.Builder()
.url(loginUrl)
.post(requestBody)
.build();
//发起请求
Call call = okHttpClient.newCall(request);
Callback callback = new Callback() {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
runOnUiThread(new Runnable() {
@Override
public void run() {
if(response.isSuccessful()){
try {
String json = response.body().string();
Log.i(TAG, "run: " + json);
//把json数据转化为对象,获取其中的属性
ResLogin resLogin = new Gson().fromJson(json, ResLogin.class);
String msg = resLogin.getMsg();
int userId = resLogin.getData().getUser_id();
Toast.makeText(OkHttpActivity.this,msg + ".欢迎用户" + userId
, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
throw new RuntimeException(e);
}
}else {
Toast.makeText(OkHttpActivity.this,"登录失败",Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OkHttpActivity.this
,"POST登录请求失败",Toast.LENGTH_SHORT).show();
}
});
}
};
call.enqueue(callback);
}
1:流程
- 设置连接属性
- ui上获取数据,Gson.toJson拼接字符串请求体
- 设置请求体数据格式
- 构建请求
- 发起请求
- 处理响应
2:一些细节
(1) 设计body参数
(2)MediaType.get(“application/json;charset=utf-8”);
媒体类型
用于定义请求体或响应体的数据格式和编码方式,是处理 JSON 数据时的常见用法。
3:登录效果
四:快捷生成JSON对应的对象
商业场景中是会创建一个实体类对象的;而非进行字符串拼接
//先用日志获取json体
String json = response.body().string();
Log.i(TAG, "run: " + json);
//在依据日志生成java对象,通过对象去获取其中的属性
new Gson().fromJson(json, ResLogin.class)
package com.xlong.networkbyjavaproject.bean;
public class ResLogin {
/**
* code : 1
* msg : 登录成功
* time : 1756263107
* data : {"token":"6c45ff48-c7ef-4666-918e-26dabb214746","user_id":4}
*/
private int code;
private String msg;
private String time;
private DataBean data;
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 String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public DataBean getData() {
return data;
}
public void setData(DataBean data) {
this.data = data;
}
public static class DataBean {
/**
* token : 6c45ff48-c7ef-4666-918e-26dabb214746
* user_id : 4
*/
private String token;
private int user_id;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
}
}