Volley用OkHttp3作為底部的框架的一個解決方案
阿新 • • 發佈:2018-12-24
Android6.0刪除了一些org.apache.http包中的一些類,所以網上的一些解決方案就會有一點不太合適。下面是我自己寫了一個解決方案。
1,首先要匯入相應的包:
compile 'com.mcxiaoke.volley:library:1.0.19'
compile 'com.squareup.okhttp3:okhttp:3.0.1',
2,重寫Volley的Volley類,支援OkHttp3
package com.yyw.volleydemo.volley.utils; import android.content.Context; import com.android.volley.RequestQueue; import com.android.volley.toolbox.DiskBasedCache; import java.io.File; import okhttp3.OkHttpClient; /** * Created by yyw on 2016/1/29. * 重寫Volley的Volley類,支援OkHttp3 */ public class Volley3 { public Volley3() { } /** * 建立一個客戶端的請求佇列 * @param context Context * @param stack OkHttpStack * @return */ public static RequestQueue newRequestQueue(Context context, OkHttpStack stack) { File cacheDir = new File(context.getCacheDir(), "volley");//快取地址:/data/data/com.yyw.volleydemo/cache/volley if(stack == null) {//如果請求的stack為空就建一個預設的 stack = new OkHttpStackImpl(new OkHttpClient.Builder().build()); } <span style="white-space:pre"> </span>//一個自定義的類,實現NetWork介面</span> BasicNetwork3 network1 = new BasicNetwork3(stack); RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1); queue1.start(); return queue1; } /** * 建立一個指定請求客戶端的請求佇列 * @param context 上下文 * @param client OkHttpClient * @return 請求佇列 */ public static RequestQueue newRequestQueueByClient(Context context, OkHttpClient client) { return newRequestQueue(context, new OkHttpStackImpl(client)); } /** * 建立一個預設請求客戶端的請求佇列 * @param context 上下文 * @return */ public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, null); } }
3,自定義的一個NetWork 模仿BasicNetwork只是把HttpStack,Response換成我們自定義的或Okhttp3中的
package com.yyw.volleydemo.volley.utils; import android.os.SystemClock; import com.android.volley.AuthFailureError; import com.android.volley.Cache; import com.android.volley.Network; import com.android.volley.NetworkError; import com.android.volley.NetworkResponse; import com.android.volley.NoConnectionError; import com.android.volley.Request; import com.android.volley.RetryPolicy; import com.android.volley.ServerError; import com.android.volley.TimeoutError; import com.android.volley.VolleyError; import com.android.volley.VolleyLog; import com.android.volley.toolbox.ByteArrayPool; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.impl.cookie.DateUtils; import java.io.IOException; import java.net.MalformedURLException; import java.net.SocketTimeoutException; import java.util.Date; import java.util.HashMap; import java.util.Map; import okhttp3.Headers; import okhttp3.Response; /** * Created by yyw on 2016/1/29. * 自定義的一個NetWork * 模仿BasicNetwork只是把HttpStack,Response換成我們自定義的或Okhttp3中的 */ public class BasicNetwork3 implements Network { protected static final boolean DEBUG; private static int SLOW_REQUEST_THRESHOLD_MS; private static int DEFAULT_POOL_SIZE; protected final OkHttpStack mHttpStack; protected final ByteArrayPool mPool; static { DEBUG = VolleyLog.DEBUG; SLOW_REQUEST_THRESHOLD_MS = 3000; DEFAULT_POOL_SIZE = 4096; } public BasicNetwork3(OkHttpStack httpStack) { this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE)); } public BasicNetwork3(OkHttpStack httpStack, ByteArrayPool pool) { this.mHttpStack = httpStack; this.mPool = pool; } public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while(true) { Response okHttpResponse = null; Object responseContents = null; HashMap responseHeaders = new HashMap(); try { HashMap e = new HashMap(); this.addCacheHeaders(e, request.getCacheEntry()); okHttpResponse = this.mHttpStack.performRequest(request, e); int networkResponse1 = okHttpResponse.code(); Map responseHeaders1 = convertHeaders(okHttpResponse.headers()); if(networkResponse1 == 304) { return new NetworkResponse(304, request.getCacheEntry().data, responseHeaders1, true); } byte[] responseContents1 = okHttpResponse.body().bytes(); long requestLifetime = SystemClock.elapsedRealtime() - requestStart; this.logSlowRequests(requestLifetime, request, responseContents1, networkResponse1); if(networkResponse1 != 200 && networkResponse1 != 204) { throw new IOException(); } return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, false); } catch (SocketTimeoutException var12) { var12.printStackTrace(); attemptRetryOnException("socket", request, new TimeoutError()); } catch (ConnectTimeoutException var13) { attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException var14) { throw new RuntimeException("Bad URL " + request.getUrl(), var14); } catch (IOException var15) { NetworkResponse networkResponse = null; if(okHttpResponse == null) { throw new NoConnectionError(var15); } int statusCode1 = okHttpResponse.code(); VolleyLog.e("Unexpected response code %d for %s", new Object[]{Integer.valueOf(statusCode1), request.getUrl()}); if(responseContents == null) { throw new NetworkError(networkResponse); } networkResponse = new NetworkResponse(statusCode1, (byte[])responseContents, responseHeaders, false); if(statusCode1 != 401 && statusCode1 != 403) { throw new ServerError(networkResponse); } attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } } } private void logSlowRequests(long requestLifetime, Request<?> request, byte[] responseContents, int status) { if(DEBUG || requestLifetime > (long)SLOW_REQUEST_THRESHOLD_MS) { VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], [rc=%d], [retryCount=%s]", new Object[]{request, Long.valueOf(requestLifetime), responseContents != null?Integer.valueOf(responseContents.length):"null", Integer.valueOf(status), Integer.valueOf(request.getRetryPolicy().getCurrentRetryCount())}); } } private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError { RetryPolicy retryPolicy = request.getRetryPolicy(); int oldTimeout = request.getTimeoutMs(); try { retryPolicy.retry(exception); } catch (VolleyError var6) { request.addMarker(String.format("%s-timeout-giveup [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)})); throw var6; } request.addMarker(String.format("%s-retry [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)})); } private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) { if(entry != null) { if(entry.etag != null) { headers.put("If-None-Match", entry.etag); } if(entry.serverDate > 0L) { Date refTime = new Date(entry.serverDate); headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); } } } private static Map<String, String> convertHeaders(Headers headers) { HashMap result = new HashMap(); for(int i = 0; i < headers.size(); ++i) { result.put(headers.name(i), headers.value(i)); } return result; } }
4,自定義的Stack介面
package com.yyw.volleydemo.volley.utils; import com.android.volley.AuthFailureError; import com.android.volley.Request; import java.io.IOException; import java.util.Map; import okhttp3.Response; /** * Created by yyw on 2016/1/28. * 自定義的Stack介面 */ public interface OkHttpStack { /** * 通過這個方法來去執行請求 * @param var1 volley中的請求 * @param var2 引數 * @return OkHttp3的請求響應 * @throws IOException * @throws AuthFailureError */ Response performRequest(Request<?> var1, Map<String, String> var2) throws IOException, AuthFailureError; }
5,提供預設的OkHttpStack實現類(參考使用OKHttp3替換Volley的底層網路請求)
package com.yyw.volleydemo.volley.utils;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by yyw on 2016/1/29.
* 預設的請求Stack例項
*/
public class OkHttpStackImpl implements OkHttpStack{
private final OkHttpClient mClient;//提供的可以克隆的OkHttpClient,例如HTTPS請求
public OkHttpStackImpl(OkHttpClient client) {
this.mClient = client;
}
@SuppressWarnings("deprecation")
private void setConnectionParametersForRequest (okhttp3.Request.Builder builder, Request<?> request)
throws IOException, AuthFailureError {
switch (request.getMethod()) {
case Request.Method.DEPRECATED_GET_OR_POST:
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.");
}
}
/**
* 如果需要對OkHttp的請求體進行修改或者新增一些內容可以在這個地方修改
* @param request
* @return
* @throws AuthFailureError
*/
protected RequestBody createRequestBody(Request request) throws AuthFailureError {
final byte[] body = request.getBody();
if (body == null) return null;
return RequestBody.create(MediaType.parse(request.getBodyContentType()), body);
}
@Override
public Response performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
int timeoutMs = request.getTimeoutMs();
OkHttpClient client = mClient.newBuilder()
.readTimeout(timeoutMs, TimeUnit.MILLISECONDS)
.connectTimeout(timeoutMs, TimeUnit.MILLISECONDS)
.writeTimeout(timeoutMs, TimeUnit.MILLISECONDS)
.build();
okhttp3.Request.Builder okHttpRequestBuilder = new okhttp3.Request.Builder();
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);
okhttp3.Request okhttp3Request = okHttpRequestBuilder.url(request.getUrl()).build();
Response okHttpResponse = client.newCall(okhttp3Request).execute();
return okHttpResponse;
}
}
好了在建立RequstQueue的時候只要呼叫Volley3的方法就可以了。
程式碼地址