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阅读 210,835评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,900评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,481评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,303评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,375评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,729评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,877评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,633评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,088评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,443评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,563评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,251评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,827评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,712评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,943评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,240评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,435评论 2 348

推荐阅读更多精彩内容