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文件中打开了使用网络权限:


将下列行添加到你的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

标签相同效果的请求体,键值对将使用一种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());
        }
    }
});

你可能感兴趣的:(okHttp)