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);
}
}