volley和底层使用okhttp3的框架的整合尝试

搜索了常用的http请求框架以后,思索:

1、对于HttpClient, Apache HttpClient早就不推荐httpclient,5.0之后干脆废弃,后续会删除。6.0删除了HttpClient。

2、HttpURLConnection 和okHttp想对比,okhttp更强大支持大文件传输,而对于HttpUrlConnection和volley(底层也是封装的HttpUrlConnetion)总是有些力不从心。

3、对于Volley框架,停止了更新,而OkkHttp得到了官方的认可,并在不断优化。

4、对于okHttp3框架因为封装的callback没有volley框架请求队列方便,故而萌生想法,将volley的底层HttpUrlConnection更改为Okhttp。

Android6.0删除了一些org.apache.http包中的一些类,网上的一些解决方案有些不太合适宜。

以下附代码:

重写Volley方法,使得和原来volley的请求队列基于一致:

package com.android.volley.oktoolbox;

import android.content.Context;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.DiskBasedCache;

import java.io.File;

import okhttp3.OkHttpClient;

/**
 * Created by Administrator on 2018-03-13.
 */

public class OkVelley {

    public OkVelley() {
    }

    /**
     * 创建一个客户端的请求队列
     * @param context Context
     * @param stack OkHttpStack
     * @return
     */
    public static RequestQueue newRequestQueue(Context context, OkHttpStack stack) {
        File cacheDir = new File(context.getCacheDir(), "volley");//缓存地址:/data/data/包名/cache/volley
        if(stack == null) {//如果请求的stack为空就建一个默认的
            stack = new OkHttpStackImpl(new OkHttpClient.Builder().build());
        }
//一个自定义的类,实现NetWork接口</span>
                OkBasicNetwork okNetwork = new OkBasicNetwork(stack);
        RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), okNetwork);
        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);
    }
}

重写BasicNetwork

package com.android.volley.oktoolbox;

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 Administrator on 2018-03-13.
 */

public class OkBasicNetwork 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 OkBasicNetwork(OkHttpStack httpStack) {
        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
    }

    public OkBasicNetwork(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;
    }
}
package com.android.volley.oktoolbox;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;


import java.io.IOException;
import java.util.Map;

import okhttp3.Response;

/**
 * Created by Administrator on 2018-03-12.
 */

public interface OkHttpStack {

     Response performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError;
}
package com.android.volley.oktoolbox;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.zhy.http.okhttp.builder.OkHttpRequestBuilder;
import com.zhy.http.okhttp.request.OkHttpRequest;

import org.apache.http.HttpResponse;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by Administrator on 2018-03-12.
 */

public class OkHttpStackImpl implements OkHttpStack {
    private OkHttpClient mClient;

    public OkHttpStackImpl(OkHttpClient client){
        this.mClient = client;
    }

    public OkHttpStackImpl(){
        this(new OkHttpClient());
    }

    /**
     *
     * @param builder okhttp的builder去创建请求
     * @param request volley的请求
     */
    public void setConnectionParameterForRequest(okhttp3.Request.Builder builder,Request<?> request) throws AuthFailureError {
        switch (request.getMethod()){
            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.PATCH:
                builder.patch(createRequestBody(request));
                break;
            case Request.Method.DEPRECATED_GET_OR_POST:
                byte[] body = request.getBody();
                if(body!=null){
                    builder.post(RequestBody.create(MediaType.parse(request.getBodyContentType()),body));
                }
                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;
            default:
                throw new RuntimeException("unkonwn method type");

        }
    }

    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 timeMs = request.getTimeoutMs();
        OkHttpClient client = mClient.newBuilder().readTimeout(timeMs, TimeUnit.SECONDS).writeTimeout(timeMs,TimeUnit.SECONDS)
                .connectTimeout(timeMs,TimeUnit.SECONDS).build();
        okhttp3.Request.Builder builder = new okhttp3.Request.Builder();
        Map<String,String> headers = request.getHeaders();
        for(final String name:headers.keySet()){
            builder.addHeader(name,headers.get(name));
        }
        for(final String name:additionalHeaders.keySet()){
            builder.addHeader(name,additionalHeaders.get(name));
        }
        setConnectionParameterForRequest(builder,request);
        okhttp3.Request okHttpRequest = builder.url(request.getUrl()).build();
        okhttp3.Response response = client.newCall(okHttpRequest).execute();
        return response;
    }
}

最后在Volley源码中RequestManager替换成自己的Volley,就可以,亲测ok

猜你喜欢

转载自my.oschina.net/u/3318187/blog/1633671
今日推荐