使用OKHttp处理Volley的底层HTTP请求

原文:http://willyan.me/2013/06/01/volley-okhttp/ 

  1. 导入Volley(目前没有官方的jar包,需要自己下载源码编译);
git clone https://android.googlesource.com/platform/frameworks/volley
  1. 导入OkHttpokhttp-urlconnection

  2. 创建OkHttpStack

/**
 * An {@link com.android.volley.toolbox.HttpStack HttpStack} implementation which
 * uses OkHttp as its transport.
 */
public class OkHttpStack extends HurlStack {
  private final OkHttpClient client;
 
  public OkHttpStack() {
    this(new OkHttpClient());
  }
 
  public OkHttpStack(OkHttpClient client) {
    if (client == null) {
      throw new NullPointerException("Client must not be null.");
    }
    this.client = client;
  }
 
  @Override protected HttpURLConnection createConnection(URL url) throws IOException {
    return client.open(url);
  }   
}
  1. 创建Volley队列
Volley.newRequestQueue(context, new OkHttpStack());

参考链接:OkHttp作者Jake Wharton的Gist

修正: 

貌似前面OkHttpStack已经不支持OkHttp2.0,见How to implement Android Volley with OkHttp 2.0? 。

现在的解决办法是:

下载或者设置对okhttp-urlconnection的依赖。

使用OkUrlFactory类重写OkHttpStack :

public class OkHttpStack extends HurlStack {
   private final OkUrlFactory okUrlFactory;
   public OkHttpStack() {
       this(new OkUrlFactory(new OkHttpClient())); 
   }
   public OkHttpStack(OkUrlFactory okUrlFactory) {
       if (okUrlFactory == null) {
           throw new NullPointerException("Client must not be null.");
       }
       this.okUrlFactory = okUrlFactory;
   }
   @Override
   protected HttpURLConnection createConnection(URL url) throws IOException {
       return okUrlFactory.open(url);
   }}

另外

这篇文章也给出了一个OkHttpStack:

package com.sottocorp.sotti.okhttpvolleygsonsample.others;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.toolbox.HttpStack;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Protocol;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
 * OkHttp backed {@link com.android.volley.toolbox.HttpStack HttpStack} that does not
 * use okhttp-urlconnection
 */
public class OkHttpStack implements HttpStack
{
    private final OkHttpClient mClient;
    public OkHttpStack(OkHttpClient client)
    {
        this.mClient = client;
    }
    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError
    {
        OkHttpClient client = mClient.clone();
        int timeoutMs = request.getTimeoutMs();
        client.setConnectTimeout(timeoutMs, TimeUnit.MILLISECONDS);
        client.setReadTimeout(timeoutMs, TimeUnit.MILLISECONDS);
        client.setWriteTimeout(timeoutMs, TimeUnit.MILLISECONDS);
        com.squareup.okhttp.Request.Builder okHttpRequestBuilder =
                new com.squareup.okhttp.Request.Builder();
        okHttpRequestBuilder.url(request.getUrl());
        Map<String, String> headers = request.getHeaders();
        for (final String name : headers.keySet())
        {
            okHttpRequestBuilder.addHeader(name, headers.get(name));
        }
        for (final String name : additionalHeaders.keySet())
        {
            okHttpRequestBuilder.addHeader(name, additionalHeaders.get(name));
        }
        setConnectionParametersForRequest(okHttpRequestBuilder, request);
        com.squareup.okhttp.Request okHttpRequest = okHttpRequestBuilder.build();
        Call okHttpCall = client.newCall(okHttpRequest);
        Response okHttpResponse = okHttpCall.execute();
        StatusLine responseStatus = new BasicStatusLine
                (
                        parseProtocol(okHttpResponse.protocol()),
                        okHttpResponse.code(),
                        okHttpResponse.message()
                );
        BasicHttpResponse response = new BasicHttpResponse(responseStatus);
        response.setEntity(entityFromOkHttpResponse(okHttpResponse));
        Headers responseHeaders = okHttpResponse.headers();
        for (int i = 0, len = responseHeaders.size(); i < len; i++)
        {
            final String name = responseHeaders.name(i), value = responseHeaders.value(i);
            if (name != null)
            {
                response.addHeader(new BasicHeader(name, value));
            }
        }
        return response;
    }
    private static HttpEntity entityFromOkHttpResponse(Response r) throws IOException
    {
        BasicHttpEntity entity = new BasicHttpEntity();
        ResponseBody body = r.body();
        entity.setContent(body.byteStream());
        entity.setContentLength(body.contentLength());
        entity.setContentEncoding(r.header("Content-Encoding"));
        if (body.contentType() != null)
        {
            entity.setContentType(body.contentType().type());
        }
        return entity;
    }
    @SuppressWarnings("deprecation")
    private static void setConnectionParametersForRequest
            (com.squareup.okhttp.Request.Builder builder, Request<?> request)
            throws IOException, AuthFailureError
    {
        switch (request.getMethod())
        {
            case Request.Method.DEPRECATED_GET_OR_POST:
                // Ensure backwards compatibility.
                // Volley assumes a request with a null body is a GET.
                byte\[\] postBody = request.getPostBody();
                if (postBody != null)
                {
                    builder.post(RequestBody.create
                            (MediaType.parse(request.getPostBodyContentType()), postBody));
                }
                break;
            case Request.Method.GET:
                builder.get();
                break;
            case Request.Method.DELETE:
                builder.delete();
                break;
            case Request.Method.POST:
                builder.post(createRequestBody(request));
                break;
            case Request.Method.PUT:
                builder.put(createRequestBody(request));
                break;
            case Request.Method.HEAD:
                builder.head();
                break;
            case Request.Method.OPTIONS:
                builder.method("OPTIONS", null);
                break;
            case Request.Method.TRACE:
                builder.method("TRACE", null);
                break;
            case Request.Method.PATCH:
                builder.patch(createRequestBody(request));
                break;
            default:
                throw new IllegalStateException("Unknown method type.");
        }
    }
    private static ProtocolVersion parseProtocol(final Protocol p)
    {
        switch (p)
        {
            case HTTP_1_0:
                return new ProtocolVersion("HTTP", 1, 0);
            case HTTP_1_1:
                return new ProtocolVersion("HTTP", 1, 1);
            case SPDY_3:
                return new ProtocolVersion("SPDY", 3, 1);
            case HTTP_2:
                return new ProtocolVersion("HTTP", 2, 0);
        }
        throw new IllegalAccessError("Unkwown protocol");
    }
    private static RequestBody createRequestBody(Request r) throws AuthFailureError
    {
        final byte\[\] body = r.getBody();
        if (body == null) return null;
        return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
    }
}