Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.toolbox.HttpStack;
import com.squareup.okhttp.Cache;
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.File;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Class to integrate volley with okhttp
*
* @author ceram1
* @see com.android.volley.toolbox.Volley
* @see com.squareup.okhttp.OkHttpClient
*/
public class OkHttpStack implements HttpStack {
/**
* Use your own way to get context. 'static' is optional.
* Constructor parameter would be better than global context.
* But you should not pass activity context if you want to reuse volley instance.
*
* Directory to save cache
*/
private static final File CACHE_DIR = GlobalContextApplication.getContext().getCacheDir();
private final OkHttpClient client = new OkHttpClient();
private OkHttpClient mClient;
public OkHttpStack() {
client.setFollowSslRedirects(true);// Allow http -> https redirect and https -> http redirect
try {
client.setCache(new Cache(new File(CACHE_DIR, "http_okhttp"), 10 * 1024 * 1024));
} catch (IOException e) {
// TODO handler error.
e.printStackTrace();
}
}
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
final String url = request.getUrl();
final com.squareup.okhttp.Request.Builder okHttpRequestBuilder = new com.squareup.okhttp.Request.Builder();
URL parsedUrl = new URL(url);
int timeoutMs = request.getTimeoutMs();
client.setConnectTimeout(timeoutMs, TimeUnit.MILLISECONDS);// OkHttp-UrlConnection -> setConnectionTimeout(long)
client.setReadTimeout(timeoutMs, TimeUnit.MILLISECONDS);// OkHttp-UrlConnection -> setReadTimeout(long)
final 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);
final com.squareup.okhttp.Request okHttpRequest = okHttpRequestBuilder.build();
final Call okHttpCall = client.newCall(okHttpRequest);
final Response okHttpResponse = okHttpCall.execute();
final int responseCode = okHttpResponse.code();
if (responseCode == -1) {
// -1 is returned by getResponseCode() if the response code could not be retrieved.
// Signal to the caller that something was wrong with the connection.
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
final Protocol protocol = okHttpResponse.protocol();
StatusLine responseStatus = new BasicStatusLine(parseProtocol(protocol), okHttpResponse.code(), okHttpResponse.message());
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
response.setEntity(entityFromOkHttpResponse(okHttpResponse));
final 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) {
final BasicHttpEntity entity = new BasicHttpEntity();
final ResponseBody body = r.body();
entity.setContent(body.byteStream());
entity.setContentLength(body.contentLength());
entity.setContentEncoding(r.header("Content-Encoding"));// Default action for UrlConnection
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:
// This is the deprecated way that needs to be handled for backwards compatibility.
// If the request's post body is null, then the assumption is that the request is
// GET. Otherwise, it is assumed that the request is a POST.
byte[] postBody = request.getPostBody();
if (postBody != null) {
// Prepare output. There is no need to set Content-Length explicitly,
// since this is handled by HttpURLConnection using the size of the prepared
// output stream.
builder.post(RequestBody.create(MediaType.parse(request.getPostBodyContentType()), postBody));
}
break;
case Request.Method.GET:
// Not necessary to set the request method because connection defaults to GET but
// being explicit here.
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 final 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);//TODO Check volley implementation because I'm not sure if this is okay.
case HTTP_2:
return new ProtocolVersion("HTTP", 2, 0);
}
throw new IllegalAccessError("Unkwown protocol");
}
private static final RequestBody createRequestBody(Request r) throws AuthFailureError {
final byte[] body = r.getBody();
if (body == null) return null;
return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
}
public OkHttpClient getClient() {
return mClient;
}
}
@moradgholi

This comment has been minimized.

Copy link

commented Apr 13, 2015

Thanks for this,
I got this exception when added this class as the second argument to the newRequestQueue method of volley when i'm going to perform a request. How can i handle this ?

04-13 11:26:00.552: E/Volley(4521): [1520] NetworkDispatcher.run: Unhandled exception java.lang.IllegalStateException: url == null
04-13 11:26:00.552: E/Volley(4521): java.lang.IllegalStateException: url == null
04-13 11:26:00.552: E/Volley(4521):     at com.squareup.okhttp.Request$Builder.build(Request.java:250)
04-13 11:26:00.552: E/Volley(4521):     at com.taxiyaab.android.util.utils.OkHttpStack.performRequest(OkHttpStack.java:88)
04-13 11:26:00.552: E/Volley(4521):     at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:96)
04-13 11:26:00.552: E/Volley(4521):     at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:112)
@moradgholi

This comment has been minimized.

Copy link

commented Apr 13, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.