1、在模块中下载或者添加依赖:
implementation 'com.squareup.okhttp3:okhttp:4.7.2'
当你看到这的时候,可能最新的稳定版已经不是3.10.0
了,你需要移步官方GitHub来查看最新版本。 官方地址 https://github.com/square/okhttp,另外不要忘了在清单文件声明访问Internet的权限,如果使用 DiskLruCache
,那还得声明写外存的权限。
2、okhttp使用
a、异步GET请求
-new OkHttpClient;
-构造Request对象;
-通过前两步中的对象构建Call对象;
-通过Call#enqueue(Callback)方法来提交异步请求;
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
b、同步GET请求
前面几个步骤和异步方式一样,只是最后一部是通过 Call#execute()
来提交请求,注意这种方式会阻塞调用线程,所以在Android中应放在子线程中执行,否则有可能引起ANR异常,Android3.0
以后已经不允许在主线程访问网络。
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.build();
final Call call = okHttpClient.newCall(request);
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = call.execute();
Log.d(TAG, "run: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
c、POST方式提交String
这种方式与前面的区别就是在构造Request对象时,需要多构造一个RequestBody对象,用它来携带我们要提交的数据。在构造 RequestBody
需要指定MediaType
,用于描述请求/响应 body
的内容类型,关于 MediaType
的更多信息可以查看 RFC 2045,RequstBody的几种构造方式:
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
String requestBody = "I am Jdqm.";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(mediaType, requestBody))
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
响应内容
http/1.1 200 OK
Date:Sat, 10 Mar 2018 05:23:20 GMT
Content-Type:text/html;charset=utf-8
Content-Length:18
Server:GitHub.com
Status:200 OK
X-RateLimit-Limit:60
X-RateLimit-Remaining:52
X-RateLimit-Reset:1520661052
X-CommonMarker-Version:0.17.4
Access-Control-Expose-Headers:ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
Access-Control-Allow-Origin:*
Content-Security-Policy:default-src 'none'
Strict-Transport-Security:max-age=31536000; includeSubdomains; preload
X-Content-Type-Options:nosniff
X-Frame-Options:deny
X-XSS-Protection:1; mode=block
X-Runtime-rack:0.019668
Vary:Accept-Encoding
X-GitHub-Request-Id:1474:20A83:5CC0B6:7A7C1B:5AA36BC8
onResponse: <p>I am Jdqm.</p>
d、POST方式提交流
RequestBody requestBody = new RequestBody() {
@Nullable
@Override
public MediaType contentType() {
return MediaType.parse("text/x-markdown; charset=utf-8");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("I am Jdqm.");
}
};
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
e、POST提交文件
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
OkHttpClient okHttpClient = new OkHttpClient();
File file = new File("test.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(mediaType, file))
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
f、POST方式提交表单
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("search", "Jurassic Park")
.build();
Request request = new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
提交表单时,使用 RequestBody
的实现类FormBody
来描述请求体,它可以携带一些经过编码的 key-value
请求体,键值对存储在下面两个集合中:
private final List<String> encodedNames;
private final List<String> encodedValues;
3、封装okhttp
a、定义接口OnFunHttpCallBack
public interface OnFunHttpCallBack {
void onFailure(int errorCode);
void onSuccess(String url, String result);
}
b、HttpMethod.java
//okhttp3封装
public class HttpMethod {
private final static String TAG = HttpMethod.class.getSimpleName();
private final static int TIME = 10000;
public final static int NETWORK_ACCESS_ERROR = 0x0001;
public final static int SERVER_BACK_ERROR = 0x0002;
private static HttpMethod m_instance = null;
private static OkHttpClient m_okHttpClient = null;
/**
* 单一实例
*/
public static HttpMethod getInstance() {
if (m_instance == null) {
m_instance = new HttpMethod();
if (m_okHttpClient == null) {
m_okHttpClient = new OkHttpClient();
//m_okHttpClient = new OkHttpClient.Builder().connectTimeout(TIME, TimeUnit.SECONDS).readTimeout(TIME, TimeUnit.SECONDS).build();
}
}
return m_instance;
}
private class HttpCallback {
private String m_strUrl = "";
private OnFunHttpCallBack m_back_http = null; //任务的回调函数
public HttpCallback(String url, OnFunHttpCallBack back) {
m_strUrl = url;
m_back_http = back;
}
/**
* AsyncHttp的回调函数
*/
private Callback m_handler = new Callback() {
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if(response.code() == 200){
String result = response.body().string();
if(m_back_http != null){
m_back_http.onSuccess(m_strUrl, result);
}
if (response.body()!=null){
response.body().close();
}
Log.i(TAG, "HTTP-Response-Url: " + m_strUrl + "-----" + result);
}else{
if(m_back_http != null){
m_back_http.onFailure(SERVER_BACK_ERROR);
}
Log.e(TAG, "HTTP-Request-Url: " + m_strUrl + " 服务器错误(Server error) " + response.code());
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
if(m_back_http != null){
m_back_http.onFailure(NETWORK_ACCESS_ERROR);
}
Log.e(TAG, "HTTP-Request-Url: " + m_strUrl + " 访问失败(Access failed)");
}
};
}
/**
* 异步GET请求
*
* @param url
* 发送请求的URL
* @param para
* 请求参数,请求参数应该是name1=value1&name2=value2的形式。
* @return URL所代表远程资源的响应
*/
public void clientGet(String url, String para, OnFunHttpCallBack back) {
Log.i(TAG, "HTTP-Request-Url: " + url + "?" + para);
String reqUrl = url;
if(para != null && !para.equals("")){
reqUrl = url + "?" + para;
}
//执行get方法
Request request = new Request.Builder()
.url(reqUrl)
.get()//默认就是GET请求,可以不写
.build();
m_okHttpClient.newCall(request).enqueue(new HttpCallback(url, back).m_handler);
}
/**
* POST方式提交表单
*
* @param url
* 发送请求的URL
* @param para
* 请求参数,请求参数应该是name1=value1&name2=value2的形式。
* @return URL所代表远程资源的响应
*/
public void clientPost(String url, String para, OnFunHttpCallBack back) {
Log.i(TAG, "HTTP-Request-Url: " + url + "?" + para);
String[] tmp1 = null;
String[] tmp2 = null;
int size = 0;
//构建表单参数
FormBody.Builder requestBuild=new FormBody.Builder();
//解析出各个参数
if (para != null && !para.equals("")) {
tmp1 = para.split("&");
size = tmp1.length;
for (int i = 0; i < size; i++) {
tmp2 = tmp1[i].split("=");
if (tmp2.length != 2) {
//return;
continue;
}
//设置请求的参数名和参数值
requestBuild.add(tmp2[0], tmp2[1]);
}
}
//执行post方法
Request request = new Request.Builder()
.url(url)
.post(requestBuild.build())
.build();
m_okHttpClient.newCall(request).enqueue(new HttpCallback(url, back).m_handler);
}
/**
* post文件上传
*
* @param url
* url
* @param file
* 文件
* @param back
* 回调接口
*/
public void upLoad(String url, File file, OnFunHttpCallBack back) {
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
Request request = new Request.Builder()
.url(url)
.post(RequestBody.create(file, mediaType))
.build();
m_okHttpClient.newCall(request).enqueue(new HttpCallback(url, back).m_handler);
}
}
c、HttpTask.java
public class HttpTask {
private String m_strUrl = "";
private String m_strPara = "";
private File m_file = null;
private OnFunHttpCallBack m_back_http = null;// 任务的回调函数
public HttpTask(String url, String para, OnFunHttpCallBack back) {
m_strUrl = url;
m_strPara = para;
m_back_http = back;
}
public HttpTask(String url, File file, OnFunHttpCallBack back) {
m_strUrl = url;
m_file = file;
m_back_http = back;
}
public void runPost() {
HttpMethod.getInstance().clientPost(m_strUrl, m_strPara, m_back_http);
}
public void runGet() {
HttpMethod.getInstance().clientGet(m_strUrl, m_strPara, m_back_http);
}
public void upLoad() {
HttpMethod.getInstance().upLoad(m_strUrl, m_file, m_back_http);
}
}