okHttp

楓葉

okHttp是一個第三方的庫被Square開發用來發送和接收接觸的Http request 和response。它建立在Okio庫上。Okio庫試圖通過共享內存池(shared memory pool)構建相比標準java I/O庫,更有效的讀寫數據。它還是Retorfit的底層庫提供更類型安全的消費REST-based API。

okHttp庫事實上提供HttpUrlConnection的接口實現。底層HttpUrlConnection類可能是oKHttp庫的底層實現。然而在oKHttp中的提供了一個分離的API,事發送以及接收網絡請求更加容易。

OkHttp v2.4也提供了一個內部管理URL的升級方法,替代java.net.URLjava.net.URI,或者android.net.Uri類,它提供了一個新的HttpUrl類,提供更加方便的方法獲取Http端口,URL解析,和處理URL字符串。


SetUp

確保在AndroidManifest.xml文件中打開了使用網絡權限:

<uses-permission android:name="android.permission.INTERNET"/>

將下列行添加到你的app/build.gradle文件中:

compile  'com.squareup.okhttp3:okhttp:3.3.0'

Note:如果將okHttp升級,導入也需要修改為:

import com.squareup.okhttp.XXXX to import okhttp3.XXXX

Note:如果你打算在OkHttp3中使用Picasso,確保添加基礎下載。這個變化是必須的直到下個版本的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()

如果需要添加其他的查詢參數,這個okHttp庫提供HttpUrl類可以方便的構造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();

如果有任何查詢效驗參數,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 來構建和HTML <form>標簽相同效果的請求體,鍵值對將使用一種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提交請求體,請求體的內容由i流寫入產成。

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

我們創建Call實例并且分發網絡同步請求:

Response response = client.newCall(requset).execute();

由于Android不允許主線程中進行網絡調用,如果你在分離的線程或者后臺服務,你可以使用synchronous調用。你也可以使用AsyncTask 用于輕量級的網絡調用。


Asynchronous Network Calls

我們也可以創建一個異步網絡調用,通過創建一個Call對象。通過使用enqueue()方法并且傳入一個匿名Callback對象,并且實現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 通常創建一個新的工作線程分發網絡請求,并且使用相同的線程去處理響應。OkHttp建立的目的是作為一個Java庫,并不處理Android框架中的限制(view 只允許在主線程中更新)。如果你需要更新任何view,你需要runOnUiThread()方法,并且將結果返回至主線程。

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

假設Request沒有被取消并且沒有connect問題,并且 onResponse()方法將被調用。他傳遞一個 Response 實例,并且可以被用來查看狀態碼,響應體,以及任何相應頭將會被返回。調用 isSuccessful() 對應實例碼相應狀態碼 2XX (i.e 200, 201)

if (!response.isSuccessful()){
    throw new IOException("Unexcepted code" + response);
}

響應頭被作為一個列表返回:

Headers responseHeaders = response.header();
for (int i = 0; i < responseHeaders.size(); i++)
{
    Log.d("DEBUG", responseHeaders.name(i) + ":" + responseHeaders.value(i));
}

我們也可以獲得響應數據,通過調用 response.body()并且調用 string() 方法去讀取整個playload,注意 response.body()只可以被調用一次,并且應該在后臺線程中調用。

Log.d("DEBUG", response.body().string());

Processing JSON data
我們調用Github API ,將會返回JSON 數據:

Request request = new Request.Builder()
    .url("https://api.github.com/users/codepath")
    .build();

我們可以解析JOSN 數據 通過JSONobject 或者 JSONArray 類,這取決于響應數據類型:

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() 方法作用在響應體將會將所有的數據加載到內存中。為了更加合理的使用內存,推薦響應進程通過 使用charStream()代替
為了使用Gson庫,我們首先要聲明類匹配JSON 響應:

static class GitUser{
    String name;
    String url;
    int id;
}

我們可以使用使用Gson解析器,將數據轉換到java模型中:

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
我們可以創建OkHttpClient并且配置cache緩存:

int cacheSize = 10 * 1024 * 1024 ;     // 10 Mib
Cache cache = new Cache(getApplication().getCacheDir(),cacheSize);
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();

我們可以控制是否取回緩存相應通過在request上設置cacheControl屬性。如過我們希望獲取緩存中的響應數據,我們可以向下面一樣配置Request實例

Request request = new Request.Builder()
    .url("http://publicobject.com/helloworld.txt")
    .cacheControl(new CacheControl.Builder().onlyIfCached().build())
    .build();

我們可以設置request請求響應response 使用noCache()

.cacheControl(new CacheControl.Builder().noCache().build())

我們也可以標明響應緩存的最大生存周期

.cacheControl(new CacheControl.Builder().maxStale(365,TimeUnit.DAYS).build())

為了取回cache相應,我們可以簡單的在響應實例上調用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());
        }
    }
});
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容