okHttp是一個第三方的庫被Square開發(fā)用來發(fā)送和接收接觸的Http request 和response仔夺。它建立在Okio庫上。Okio庫試圖通過共享內(nèi)存池(shared memory pool)構(gòu)建相比標(biāo)準(zhǔn)java I/O庫狮腿,更有效的讀寫數(shù)據(jù)。它還是Retorfit的底層庫提供更類型安全的消費REST-based API猜旬。
okHttp庫事實上提供HttpUrlConnection的接口實現(xiàn)桩砰。底層HttpUrlConnection類可能是oKHttp庫的底層實現(xiàn)。然而在oKHttp中的提供了一個分離的API凌节,事發(fā)送以及接收網(wǎng)絡(luò)請求更加容易钦听。
OkHttp v2.4也提供了一個內(nèi)部管理URL的升級方法,替代java.net.URL
倍奢,java.net.URI
朴上,或者android.net.Uri
類,它提供了一個新的HttpUrl
類卒煞,提供更加方便的方法獲取Http端口痪宰,URL解析,和處理URL字符串畔裕。
SetUp
確保在AndroidManifest.xml
文件中打開了使用網(wǎng)絡(luò)權(quán)限:
<uses-permission android:name="android.permission.INTERNET"/>
將下列行添加到你的app/build.gradle
文件中:
compile 'com.squareup.okhttp3:okhttp:3.3.0'
Note:如果將okHttp升級衣撬,導(dǎo)入也需要修改為:
import com.squareup.okhttp.XXXX to import okhttp3.XXXX
Note:如果你打算在OkHttp3中使用Picasso,確保添加基礎(chǔ)下載扮饶。這個變化是必須的直到下個版本的Picasso
dependencies{
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.0.2'
}
Sending and Receiving Network Requests
首先 我們初始化okHttpclient 并且建立一個 Request實例
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build()
如果需要添加其他的查詢參數(shù)具练,這個okHttp庫提供HttpUrl
類可以方便的構(gòu)造URL:
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://ajax.googleapis.com/ajax/services/search/images").newBuilder();
urlBuilder.addQueryParameter("v", "1.0")甜无;
urlBuilder.addQueryParameter("q", "android")扛点;
urlBuilder.addQueryParameter("rsz", "8");
Sring url = urlBuilder.build().toString()岂丘;
Request request = new Request.Builder()
.url(url)
.build();
如果有任何查詢效驗參數(shù)陵究,request可以添加效驗頭部:
Request request = new Request.Builder()
.header("Authorization", "token abcd")
.url("https://api.github.com/users/codepath")
.build();
Http Post Json
public static final MediaType JSON = MediaType.parse("application/json; charset = utf-8")
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException{
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
if(response.isSuccessful())
{
return response.body().string();
}else{
throw new IOException("Unexpected code " + response);
}
}
Htttp Post 提交鍵值對
使用FormEncodingBuilder 來構(gòu)建和HTML <form>標(biāo)簽相同效果的請求體奥帘,鍵值對將使用一種HTML兼容形式的URL編碼來進行編碼畔乙。
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException{
RequestBody formBody = new FormEncodingBuilder()
.add("platform", "android")
.add("name", "bug")
.add("subject", "XXXXXXXXX")
.build();
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (response,isSuccessful()){
return response.body().string();
}else{
throw new IOException("Unexpected code" + response)
}
}
Post 方式提交流
以流的方式POST提交請求體,請求體的內(nèi)容由i流寫入產(chǎn)成翩概。
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 {
RequestBody requestBody = new RequsetBody(){
@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) + " x " + i;
}
return Integer.toString(n);
}
};
Request request = new Request.Builder()
.url("[https://api.github.com/markdown/raw](https://api.github.com/markdown/raw)")
.post(requestBody)
.build();
}
Post 方式提交文件
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
private void run() throws Exception{
File file = new File("README.md");
Request request = new Request.Builder()
.url("[https://api.github.com/markdown/raw](https://api.github.com/markdown/raw)")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
}
Synchronous Network Calls
我們創(chuàng)建Call實例并且分發(fā)網(wǎng)絡(luò)同步請求:
Response response = client.newCall(requset).execute()牲距;
由于Android不允許主線程中進行網(wǎng)絡(luò)調(diào)用返咱,如果你在分離的線程或者后臺服務(wù),你可以使用synchronous調(diào)用牍鞠。你也可以使用AsyncTask 用于輕量級的網(wǎng)絡(luò)調(diào)用咖摹。
Asynchronous Network Calls
我們也可以創(chuàng)建一個異步網(wǎng)絡(luò)調(diào)用,通過創(chuàng)建一個Call
對象难述。通過使用enqueue()方法并且傳入一個匿名Callback對象萤晴,并且實現(xiàn)onFailure()和onResponse()方法
client.newCall(request).enqueue(new Callback(){
@Override
public void onFailure(Call call,IOException e)
{
e.printStackTrace()胁后;
}
@Override
public void onResponse(Call call店读,final Response response) throws IOException
{
if(!response.isSuccessful()){
throw new IOException("Unexpected code " + response);
}
}
})
OkHttp 通常創(chuàng)建一個新的工作線程分發(fā)網(wǎng)絡(luò)請求攀芯,并且使用相同的線程去處理響應(yīng)屯断。OkHttp建立的目的是作為一個Java庫,并不處理Android框架中的限制(view 只允許在主線程中更新)侣诺。如果你需要更新任何view殖演,你需要runOnUiThread()
方法,并且將結(jié)果返回至主線程年鸳。
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String responseData = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
TextView myTextView = (TextView)findViewById(R.id.myTextView);
myTextView.setText(responseData);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
Processing Network Response
假設(shè)Request沒有被取消并且沒有connect問題趴久,并且 onResponse()方法將被調(diào)用。他傳遞一個 Response 實例搔确,并且可以被用來查看狀態(tài)碼彼棍,響應(yīng)體,以及任何相應(yīng)頭將會被返回膳算。調(diào)用 isSuccessful() 對應(yīng)實例碼相應(yīng)狀態(tài)碼 2XX (i.e 200, 201)
if (!response.isSuccessful()){
throw new IOException("Unexcepted code" + response);
}
響應(yīng)頭被作為一個列表返回:
Headers responseHeaders = response.header();
for (int i = 0; i < responseHeaders.size(); i++)
{
Log.d("DEBUG", responseHeaders.name(i) + ":" + responseHeaders.value(i));
}
我們也可以獲得響應(yīng)數(shù)據(jù)座硕,通過調(diào)用 response.body()并且調(diào)用 string() 方法去讀取整個playload,注意 response.body()只可以被調(diào)用一次畦幢,并且應(yīng)該在后臺線程中調(diào)用坎吻。
Log.d("DEBUG", response.body().string());
Processing JSON data
我們調(diào)用Github API ,將會返回JSON 數(shù)據(jù):
Request request = new Request.Builder()
.url("https://api.github.com/users/codepath")
.build();
我們可以解析JOSN 數(shù)據(jù) 通過JSONobject 或者 JSONArray 類宇葱,這取決于響應(yīng)數(shù)據(jù)類型:
client.newCall(request).enqueue(new Callback(){
@Override
public void onResponse(Call call, final Response response) throws IOException{
try{
String responseData = response.body().string();
JSONObject json = new JSONObject(responseData);
final String owner = json.getString("name");
}catch (JSONException e )
{
}
}
});
Processing JSON data with Gson
注意 sting() 方法作用在響應(yīng)體將會將所有的數(shù)據(jù)加載到內(nèi)存中瘦真。為了更加合理的使用內(nèi)存,推薦響應(yīng)進程通過 使用charStream()
代替
為了使用Gson庫黍瞧,我們首先要聲明類匹配JSON 響應(yīng):
static class GitUser{
String name;
String url;
int id;
}
我們可以使用使用Gson解析器诸尽,將數(shù)據(jù)轉(zhuǎn)換到j(luò)ava模型中:
final Gson gson = new Gson();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, final Response response) throws IOException {
GitUser user = gson.fromJson(response.body().charStream(), GitUser.class);
}
}
Caching Network Responses
我們可以創(chuàng)建OkHttpClient并且配置cache緩存:
int cacheSize = 10 * 1024 * 1024 ; // 10 Mib
Cache cache = new Cache(getApplication().getCacheDir()印颤,cacheSize)您机;
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
我們可以控制是否取回緩存相應(yīng)通過在request上設(shè)置cacheControl屬性。如過我們希望獲取緩存中的響應(yīng)數(shù)據(jù),我們可以向下面一樣配置Request實例
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.cacheControl(new CacheControl.Builder().onlyIfCached().build())
.build();
我們可以設(shè)置request請求響應(yīng)response 使用noCache()
.cacheControl(new CacheControl.Builder().noCache().build())
我們也可以標(biāo)明響應(yīng)緩存的最大生存周期
.cacheControl(new CacheControl.Builder().maxStale(365际看,TimeUnit.DAYS).build())
為了取回cache相應(yīng)咸产,我們可以簡單的在響應(yīng)實例上調(diào)用cacheResponse()
Call call = client.newCall(request);
call.enqueue(new Callback(){
@Override
public void onFailure(Call call, IOException e){
}
@Override
public void onResponse(Call call, final Response response) throws IOException
{
final Response text = response.cacheResponse();
if(text != null){
Log.d("here", text.toString());
}
}
});