[关闭]
@SmartDengg 2015-12-23T08:38:44.000000Z 字数 4732 阅读 1332

【译】使用OkHttp

OkHttp是Square公司出品的一个三方类库,用于发送和接受基于HTTP的网络请求。它基于Okio,一个试图通过创建共享内存池的方式处理数据的读和写,比标准的Java I/O类库更高效的类库。它也是Retrofit的底层类库,提供类型安全的基于REST的API请求。

OkHttp实际上实现了HttpUrlConnection,并且在Android 4.4及以后版本的源码中已经使用Okhttp代替HttpUrlConnection了。因此当我们按照这个章节的指导进行操作的时候,HttpUrlConnection类可能来自于OkHttp类库。然而,OkHttp提供独立的API,将发送和接收网络请求变得更简单,这正是这篇文章所要描述的。

设置

确保AndroidManifest.xml文件中能够得到网络权限。

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

然后,仅仅将这一行添加到app/build.gradle文件中

compile 'com.squareup.okhttp:okhttp:2.7.0'

发送和接收网络请求

首先,我们必须初始化一个OkHttpClient实例,然后创建一个Request对象。

  1. OkHttpClient client = new OkHttpClient();
  2. Request request = new Request.Builder()
  3. .url("http://publicobject.com/helloworld.txt")
  4. .build();

如果需要添加一些请求参数,可以通过OkHttp提供的HttpUrl类构造该URL:

  1. HttpUrl.Builder urlBuilder = HttpUrl.parse("https://ajax.googleapis.com/ajax/services/search/images")
  2. .newBuilder();
  3. urlBuilder.addQueryParameter("v", "1.0");
  4. urlBuilder.addQueryParameter("q", "android");
  5. urlBuilder.addQueryParameter("rsz", "8");
  6. String url = urlBuilder.build().toString();
  7. Request request = new Request.Builder()
  8. .url(url)
  9. .build();

如果需要Authenticated作为参数,也可以添加到请求头中:

  1. Request request = new Request.Builder()
  2. .header("Authorization", "token abcd")
  3. .url("https://api.github.com/users/codepath")
  4. .build();

同步网络请求

我们可以创建一个call对象,然后同步调度网络请求:

  1. Response response = client.newCall(request).execute();

因为Android不允许在主线程处理请求网络,所以这种同步调用方式,只能在独立的工作线程或者后台Service中调用。你也可以使用AsyncTask处理轻量级网络操作。

异步网络请求

我们也可以通过创建call来处理异步网络请求,使用enqueue()方法,然后传入一个匿名Callback,并实现onFailure()onResponse()方法。

  1. // Get a handler that can be used to post to the main thread
  2. client.newCall(request).enqueue(new Callback() {
  3. @Override
  4. public void onFailure(Request request, IOException e) {
  5. e.printStackTrace();
  6. }
  7. @Override
  8. public void onResponse(final Response response) throws IOException {
  9. if (!response.isSuccessful()) {
  10. throw new IOException("Unexpected code " + response);
  11. }
  12. }
  13. }

这种场景下OkHttp会创建一个新的工作线程来调度网络请求,然后在该线程中回调Response。它主要是一个Java库,所以不要在这个方法里面做Android Framework中明令禁止的事情,比如不允许在非UI线程中更新View。如果你需要更新任何View,可以使用runOnUiThread()或者将结果发送到主线程。点击这个指南可以了解更多。

处理网络结果

假设请求没有被取消并且网络连接也毫无问题,onResponse()将会被回调。它传递一个Response对象,可以通过它来检查Status CodeResponse BodyHeader或者所有返回的数据。例如可以通过调用isSuccessful()来判断返回的状态码是否为2xx(比如:200,201等)。

  1. if (!response.isSuccessful()) {
  2. throw new IOException("Unexpected code " + response);
  3. }

响应头也可以通过集合的形式获取:

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

响应头也可以使用response.header()直接获取:

  1. String header = response.header("Date");

我们也可以通过调用response.body()获得响应数据,然后调用string()读取整个Body的原始数据。值得一提的是,response.body()只能运行一次,并且应该在后台线程中完成操作。

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

处理Json数据

假设我们访问了Github API,并返回了一串Json数据。

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

我们可以通过Decode将响应结果转换成JSONObject或者JSONArray

  1. client.newCall(request).enqueue(new Callback() {
  2. @Override
  3. public void onResponse(final Response response) throws IOException {
  4. try {
  5. String responseData = response.body().string();
  6. JSONObject json = new JSONObject(responseData);
  7. final String owner = json.getString("name");
  8. } catch (JSONException e) {
  9. }
  10. }
  11. });

使用Gson处理Json数据

需要注意的是,response.body().string()会将整个数据加载到内存中。为了更有效的使用内存,建议使用charStream()方法将response转换成Stream,然后进行处理。然而这种方法需要使用Gson库。详情请阅读这篇使用说明

使用Gson,必须首先定义一个与Json Response有直接映射关系的类。(译者注:Gson解析通过反射完成,不需要额外定义setter方法):

  1. static class GitUser {
  2. String name;
  3. String url;
  4. int id;
  5. }

Gson可以将数据直接转换成Java Model:

  1. // Create new gson object
  2. final Gson gson = new Gson();
  3. // Get a handler that can be used to post to the main thread
  4. client.newCall(request).enqueue(new Callback() {
  5. // Parse response using gson deserializer
  6. @Override
  7. public void onResponse(final Response response) throws IOException {
  8. // Process the data on the worker thread
  9. GitUser user = gson.fromJson(response.body().charStream(), GitUser.class);
  10. // Access deserialized user object here
  11. }
  12. }

发送Authenticated请求

OkHttp有个机制,它允许使用 interceptors(拦截器)修改出站请求。一个常见的用例就是OAuth Protocol(开放协议),它需要使用私钥签名的网络请求。在OkHttp signpost library中使用了SignPost library,然后通过interceptor标记每一个出站请求。这样调用者就不需要记住每一个请求,省去了重复标记的步骤:

  1. OkHttpOAuthConsumer consumer = new OkHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
  2. consumer.setTokenWithSecret(token, secret);
  3. okHttpClient.interceptors().add(new SigningInterceptor(consumer));

指导方针

阅读Square的官方指导recipe guide以及其他使用OkHttp的场景。

参考文献

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注