Android——使用OkHttp(含各種請求方法)
支援 SPDY ,共享同一個 Socket 來處理同一個伺服器的所有請求
1、如果 SPDY 不可用,則通過連線池來減少請求延時
2、無縫的支援GZIP來減少資料流量
3、快取響應資料來減少重複的網路請求
OkHttp 處理了很多網路疑難雜症:會從很多常用的連線問題中自動恢復。
一、測試使用我們的OKHttp第三方庫
1.第一步我們需要去建立一個 OKHttpClient 物件
OkHttpClient okHttpClient = new OkHttpClient();
2.下一步我們還需要一個 Request 物件,她可以已如下方式被建立
Request request = new Request.Builder()
.url(requestUrl)
.build();
requestUrl是一個字串變數,表示這個URL是為了JSON請求(The requestUrl is a String variable representing the Url for the JSON request.)
3.再下一步我們需要例項化一個 Call 物件
Call call = okHttpClient.newCall(request);
Call物件會取走我們的 okHttpClient物件 和 我們的 request物件。
4.在例項化Call物件後,我們現在可以 Execute(執行)它。Executing一個Call後將會返回一個 Response,
並且會丟擲一個 IOException的異常,這就是為什麼們會用一個try,catch塊包裹她。
try{
Response response = call.execute();
}catch (IOException e){
e.printStackTrace();
}
5.執行完我們的Call後,我們需要通過使用 response.isSuccessful()來檢查Call物件是否執行成功,
通過response.isSuccessful()的返回值為true或者是false來判斷。
這我們僅僅是一個測試,如果Call成功的話,我們將會通過Log來列印我們的response。
try{
Response response = call.execute();
if(response.isSuccessful()){
//The call was successful.print it to the log
Log.v("OKHttp",response.body().string());
}
}catch(IOException e){
e.printStackTrace();
}
6.測試Code!
這是新手一個常見的錯誤。在Android中不允許任何網路的互動在主執行緒中進行。
It disallows it to force developers to use asynchronous callbacks.
但是現在,我們的程式碼看起來看起來十分的號好!下面我們來看看如何修復這個問題。
7.Fix issue
為了修補這個問題,我們只需要讓我們的Call執行在非主執行緒內,
所以利用一個 asynchronous callback(非同步的callBack)。
讓我們call非同步的方法是通過呼叫我們Call物件的 enqueue()方法。
call.enqueue(new Callback()) {
@Override
public void onFailure( Request request, IOException e ) {
}
@Override
public void OnResponse( Response response) throws IOException {
try {
if(response.isSuccessful()){
//The call was successful. print it to the log
log.v("OKHttp",response.body.string());
}
}catch (IOException e) {
e.printStackTrace();
}
}
});
8.在我們再次執行我們的code之前,我們還需要再改一改。如果我們想要現在執行她,我們可能還會接收到錯誤的提示,
因為我們應用的程式沒有得到相應的相應的網路許可權。所以我們需要再AndroidManifest.xml中新增應用許可權。
<uses-permission android:name="android.permission.INTERNET"/>
9.當我們執行完code後,我們將接受到如下的log輸出:
10.
This means, we are now able to execute asynchronous network calls and use the data inside the callback method, when it is ready!
onResponse回撥的引數是response,一般情況下,
比如我們希望獲得返回的字串,可以通過response.body().string()獲取;
如果希望獲得返回的二進位制位元組陣列,則呼叫response.body().bytes();
如果你想拿到返回的inputStream,則呼叫response.body().byteStream()
二、請求方法介紹
1、HTTP請求方法
- 同步GET請求
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
Response類的string()方法會把文件的所有內容載入到記憶體,適用於小文件,
對應大於1M的文件,應使用流()的方式獲取。
response.body().byteStream()
- 非同步GET請求
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
});
}
讀取響應會阻塞當前執行緒,所以發起請求是在主執行緒,回撥的內容在非主執行緒中。
- POST方式提交字串
private static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
因為整個請求體都在記憶體中,應避擴音交1M以上的檔案。
- POST方式提交流
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody requestBody = new RequestBody() {
@Override
public MediaType contentType() {
return MEDIA_TYPE_MARKDOWN;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("Numbers\n");
sink.writeUtf8("-------\n");
for (int i = 2; i <= 997; i++) {
sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
}
}
private String factor(int n) {
for (int i = 2; i < n; i++) {
int x = n / i;
if (x * i == n) return factor(x) + " × " + i;
}
return Integer.toString(n);
}
};
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
使用Okio框架以流的形式將內容寫入,這種方式不會出現記憶體溢位問題。
- POST方式提交檔案
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
File file = new File("README.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
- POST方式提交表單
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody formBody = new FormEncodingBuilder()
.add("search", "Jurassic Park")
.build();
Request request = new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
表單的每個Names-Values都進行了URL編碼。如果伺服器端介面未進行URL編碼,可定製個 FormBuilder。
- 檔案上傳(相容html檔案上傳)
private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}