本文轉載自:http://www.cnblogs.com/qifengshi/p/5405550.html
okHttp是一個http請求框架,相當於android原生的httpclient和httpURLConnectiond的封裝,讓寫法更加簡單,可以處理更加復雜的網絡請求;
OkHttp使用:
Gradle導入:
compile 'com.squareup.okhttp3:okhttp:3.2.0' compile 'com.squareup.okio:okio:1.6.0'
或者用meven導入;
使用get請求:get分為get同步請求和get異步請求:
首先定義一個okhttpclient和Requeset:
private OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().
url("http://www.baidu.com").
build();
也可以在創建Requeset的時候就傳入參數:
Request request = new Request.Builder().
url("http://www.baidu.com").
addHeader("User-Agent","android").
header("Content-Type","text/html; charset=utf-8").
build();
通過addHeader和header方法為請求增加請求頭部,注意使用header(name, value)可以設置唯一的name、value。如果已經有值,舊的將被移除,然后添加新的。使用addHeader(name, value)可以添加多值(添加,不移除已有的)。
同步的get方法,通過client.newCall(request).execute()方法得到請求的response.
Response response = okHttpClient.newCall(request).execute();
OkHttp封裝了很多處理response的方法,比如response.headers()的得到headers
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
System.out.println(headers.name(i) + ": " + headers.value(i)); }
就得到請求頭的內容:
Date: Mon, 18 Apr 2016 05:23:43 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: Keep-Alive Vary: Accept-Encoding Set-Cookie: BAIDUID=A323EC9BF678C0EB78E20741FD71211B:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com Set-Cookie: BIDUPSID=A323EC9BF678C0EB78E20741FD71211B; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com Set-Cookie: PSTM=1460957023; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com Set-Cookie: BDSVRTM=0; path=/ Set-Cookie: BD_HOME=0; path=/ Set-Cookie: H_PS_PSSID=1434_19672_18281_19690_17948_18205_19558_15952_12257; path=/; domain=.baidu.com P3P: CP=" OTI DSP COR IVA OUR IND COM " Cache-Control: private Cxy_all: baidu+2db7793e0e32b9f6c20be8f623e1ae43 Expires: Mon, 18 Apr 2016 05:22:55 GMT X-Powered-By: HPHP Server: BWS/1.1 X-UA-Compatible: IE=Edge,chrome=1 BDPAGETYPE: 1 BDQID: 0xfacc6fc10004ca96 BDUSERID: 0 OkHttp-Sent-Millis: 1460957021226 OkHttp-Received-Millis: 1460957021430
響應報文的實體可以通過response.body().string()獲取;如果希望獲得返回的二進制字節數組,則調用response.body().bytes();如果你想拿到返回的inputStream,則調用response.body().byteStream()。
異步的get請求得到的response方法是通過如下方法:
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
在onResponse方法中,執行請求成功的代碼,onFailure方法中,執行請求失敗的代碼
下面給一個完整的異步get的栗子
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.text.method.ScrollingMovementMethod;
import android.widget.TextView;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
private OkHttpClient okHttpClient = new OkHttpClient();
public TextView show;
public Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show = (TextView) findViewById(R.id.show);
show.setMovementMethod(ScrollingMovementMethod.getInstance());
Request request = new Request.Builder().
url("http://www.baidu.com").
addHeader("User-Agent", "android").
header("Content-Type", "text/html; charset=utf-8").
get().
build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final Headers headers = response.headers();
final String str = response.body().string();
handler.post(new Runnable() {
@Override
public void run() {
for (int i = 0; i < headers.size(); i++) {
show.append(headers.name(i) + ": " + headers.value(i));
show.append(str);
}
}
});
}
});
}
}
其實按照官網說的,回調是發生在response 的headers准備好就發生的,所以有時候請求response的實體部分會發生阻塞。
post請求——鍵值對為參數。
post請求和get請求除了在構建request上面不同以外,在處理response上面都是一樣的,所以下面我們只討論一下post構建request,當然post也是支持同步post和異步post的,可以參考get方法。
在構建post的request時候,首先用FormBody.Builder去構建request的body部分,栗子如下,當然這是OKHttp3的方法.
FormBody.Builder builder = new FormBody.Builder();
for(int i = 0 ; i < key.size() ;i ++){
builder.add(key.get(i),value.get(i));
}
RequestBody body = builder.build();
builder中add的是要加入的參數鍵值對。得到要構造的body后用
Request request = new Request.Builder().url(url).post(body).build();
獲得請求的request,后面的操作就和get方法是一樣的,這里可以參考異步get的栗子,構建一個post的request.下面的寫法原封不變。
post請求--多種類型的body
上文已經說了post和get的用法主要在構建不同的request上面,所以接下來我們主要討論的也是如何構建request.
參考上面,我們首先要創建一個requestBody,我們可以用下面的方式去構建,當然這也是okhttp3的方法
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
已表單上傳的形式去提交post。我們看一下builder的方法
/** Add a part to the body. */
public Builder addPart(RequestBody body) {
return addPart(Part.create(body));
}
/** Add a part to the body. */
public Builder addPart(Headers headers, RequestBody body) {
return addPart(Part.create(headers, body));
}
/** Add a form data part to the body. */
public Builder addFormDataPart(String name, String value) {
return addPart(Part.createFormData(name, value));
}
/** Add a form data part to the body. */
public Builder addFormDataPart(String name, String filename, RequestBody body) {
return addPart(Part.createFormData(name, filename, body));
}
從這里我們可以看出可以直接用 public Builder addFormDataPart(String name, String filename, RequestBody body)上傳一個File,最后一個參數是請求的實體,可以通過 RequestBody.create(final MediaType contentType, final File file) 獲得,而MediaType則可以通過下面方法獲得
//調用judgeType方法
private static final MediaType MEDIA_TYPE = MediaType.parse(judgeType(fileName);
//judge方法如下
private String judgeType(String path) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(path);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
由於我后台能力比較渣,這里用一個官網的例子來實現一遍我剛才討論的方法。
MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("image", "logo-square.png",
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")));
RequestBody requestBody = builder.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " +"9199fdef135c122")
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
當然除了這個方法以外,調用如下方法也是可以的,我們可以利用name和filename自己構造Header傳上去。
public Builder addPart(Headers headers, RequestBody body) {
return addPart(Part.create(headers, body))
栗子如下:
builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + name + "\"; filename=\"" + fileName + "\""),fileBody);
后面的寫法和上面類似,這樣我們就實現了文件上傳的寫法。
文件下載
剛才我們上面已經說了,希望獲得返回的二進制字節數組,則調用response.body().bytes();如果你想拿到返回的inputStream,則調用response.body().byteStream()。換句話說,文件的下載可以簡單的通過get請求,得到相應的response,在把他的實體轉換成二進制流寫入文件,就是實現了文件的下載。主要的寫法就是文件的讀寫,跟OKHttp關系不大,當然我們也可以用okio來實現文件的讀寫,這里水平有限就不介紹了。下面給一個簡單的例子。
private void _download(final String url, final String destFileDir, final ResultCallback callback) {
final Request request = new Request.Builder().url(url).build();
final Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream is = null;
byte[] buf = new byte[2048];
int len = 0;
FileOutputStream fos = null;
try {
is = response.body().byteStream();
File file = new File(destFileDir, getFileName(url));
fos = new FileOutputStream(file);
while((len = is.read(buf)) != -1){
fos.write(buf,0,len);
}
fos.flush();
//....省略后續對已經保存的文件的操作
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (is != null) is.close();
} catch (IOException e) {
}
try
{
if (fos != null) fos.close();
} catch (IOException e)
{
}
}
}
});
}
