美文网首页
Android:封装网络请求库Volley结合Okhttp

Android:封装网络请求库Volley结合Okhttp

作者: rechen | 来源:发表于2018-09-13 15:43 被阅读0次

    1. 前言

    在拷贝Github的源码到本地时,有一个技巧,能节约很多修改package和import的时间

    1. 在Github下载源码的zip包到本地,解压
    2. 将下载的源码的java目录下的文件夹全部拷贝到目标位置的java目录下
    3. 修复一些第三方依赖的问题
    4. 再将目标位置的java目录下的包名整体移动到希望的包下面

    这样做的好处时,让编辑器自动完成包名和导包的替换,不用手动替换。

    2. 为什么要volley结合okhttp

    okhttp是非常优秀的网络请求库,网络传输层非常好用,支持http和https,被google官方接受,但只是单纯的网络操作工具,没有封装异步操作。而volley是google推出的,可以取消请求,有请求缓存功能,在高并发且数据量小的场景非常适合,但是在大数据量请求表现糟糕,并且不支持https。因此将这两种结合起来,采用volley的高并发调度和缓存功能,采用okhttp网络传输功能。

    3. 结合volley和okhttp的步骤

    volley把网络传输层通过HttpStack接口的方式暴露出来,因此可以实现这个接口来替换Volley默认的网络传输层的实现

    整个网络请求的流程:

    1. 首先将volley的Request转换为okhttp的Request
    2. 调用okhttp的网络传输层,将okhttp的Request转换为okhttp的Response
    3. 将okhttp的Response转换为apache的Response
    4. 将apache的Response转换为volley的Response

    整合volley和okhttp的步骤:

    1. 实现OkHttpHelper类,将okhttp的网络操作封装一下
    2. 实现OkHttpInterceptor类,用于输出请求和返回的日志
    3. 实现OkHttpStack类,实现volley的HttpStack接口。内部主要完成:解析和处理volley的request的header、解析和处理volley的request的body、将volley的request的header和body设置到okhttp的request上、用okhttp传输网络层得到okhttp的response、解析okhttp的response的header、解析okhttp的response的body、将okhttp的response的header和body设置到apache的HttpResponse上。
    4. 实现HeaderStorage类,将请求的header数据(包括cookie数据)缓存起来
    5. 实现CookieStorage类,将请求的header中的cookie数据和返回的cookie数据缓存起来,供下次请求使用
    6. 实现CustomDiskCache类,指定volley的硬盘缓存策略
    7. 实现SecurityUtil类,解决okhttp的https证书校验问题
    8. 实现BaseCustomJsonRequest类和其子类CustomJsonObjectRequest和CustomJsonArrayRequest类,内部兼容json类型的请求数据和form表单类型的请求数据。
    9. 实现CustomJsonBody类,继承了RequestBody类,封装json数据的string类型转换为okhttp接受的RequestBody类型。
    10. 实现NetworkConfig类,完成整个网络库所提供对外的所有配置,包括超时时间、连接池数量、域名设置等等
    11. 实现NetworkLogger类,完成网络库关键数据的打印功能
    12. 实现NetworkManager类,内部实现网络库的初始化,已经网络请求的添加。这个类是暴露给外部使用的
    13. okhttp源码的一些修改,okhttp不只是针对android平台的,因此其源码设计具有移植性。所以需要稍微改动使其支持android平台

    4. 关键位置讲解

    因为代码较多,不可能全部都拿来讲,因此这里只把关键的一个地方讲一下,其他地方可查阅源代码

    首先导入volley和okhttp所需要的依赖

    apply plugin: 'com.android.library'
    
    android {
        compileSdkVersion 28
        /* volley依赖,这个是为了在android 6.0以上的高版本引用HttpClient*/
        useLibrary 'org.apache.http.legacy'
    
    
        defaultConfig {
            minSdkVersion 15
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        implementation 'com.android.support:appcompat-v7:28.0.0-rc02'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    
        /* okhttp依赖 */
        implementation 'com.squareup.okio:okio:1.14.0'
        implementation 'com.google.code.findbugs:jsr305:2.0.1'
        implementation 'org.conscrypt:conscrypt-openjdk-uber:1.1.3'
    }
    

    OkHttpHelper封装了okhttp的网络操作,使其所有操作共享一个连接池

    public class OkHttpHelper {
    
        private static OkHttpClient mClientHttp = null;
        private static OkHttpClient mClientHttps = null;
    
        private final static Object clientHttpLock = new Object();
        private final static Object clientHttpsLock = new Object();
    
        private final static CustomCookieJar mCookieJar = new CustomCookieJar();
    
        private static OkHttpClient getClientHttp() {
            return getClientHttp(0);
        }
    
        private static OkHttpClient getClientHttp(int timeOut) {
            if (mClientHttp == null) {
                synchronized (clientHttpLock) {
                    if (mClientHttp == null) {
                        mClientHttp = getBuilder(false, timeOut).build();
                    }
                }
            }
            return mClientHttp;
        }
    
        private static OkHttpClient getClientHttps() {
            return getClientHttps(0);
        }
    
        private static OkHttpClient getClientHttps(int timeOut) {
            if (mClientHttps == null) {
                synchronized (clientHttpsLock) {
                    if (mClientHttps == null) {
                        mClientHttps = getBuilder(true, timeOut).build();
                    }
                }
            }
            return mClientHttps;
        }
    
        public static OkHttpClient getClient(boolean isHttps) {
            return getClient(isHttps, 0);
        }
    
        public static OkHttpClient getClient(boolean isHttps, int timeOut) {
            if (isHttps) {
                return getClientHttps(timeOut);
            } else {
                return getClientHttp(timeOut);
            }
        }
    
        private static OkHttpClient.Builder getBuilder(boolean isHttps, int timeOut) {
            NetworkConfig config = NetworkManager.getInstance().getNetworkConfig();
    
            int readTimeOut = config.getReadTimeout() / 1000;
            int writeTimeOut = config.getWriteTimeout() / 1000;
            int connTimeOut = config.getConnTimeout() / 1000;
    
            if (timeOut > 0) {
                timeOut = timeOut / 1000; //转换成 秒
                connTimeOut = timeOut;
                readTimeOut = timeOut;
                writeTimeOut = timeOut;
            }
    
            OkHttpClient.Builder builder = new OkHttpClient().newBuilder()
                    .readTimeout(readTimeOut, TimeUnit.SECONDS)
                    .writeTimeout(writeTimeOut, TimeUnit.SECONDS)
                    .connectTimeout(connTimeOut, TimeUnit.SECONDS)
                    .cookieJar(mCookieJar);
    
            if (isHttps) {
                SSLSocketFactory sslSocketFactory = SecurityUtil.getSSLSocketFactory();
                if (null != sslSocketFactory) {
                    builder.sslSocketFactory(sslSocketFactory);
                }
                builder.hostnameVerifier(SecurityUtil.getHostnameVerifier());
            }
    
            builder.addInterceptor(new OkHttpInterceptor());
            return builder;
        }
    }
    

    OkHttpInterceptor只要用于okhttp请求和返回的日志打印

    /**
     * okhttp拦截器,用于日志打印
     */
    public class OkHttpInterceptor implements Interceptor {
    
        private static final String NEWLINE = "\n";
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            long requestTime = System.currentTimeMillis();
            Request request = chain.request();
    
            StringBuilder sb = new StringBuilder();
            sb.append("请求url为:").append(request.url()).append(NEWLINE);
            sb.append("请求方式为:").append(request.method()).append(NEWLINE);
    
            // 打印请求的header
            Headers requestHeaders = request.headers();
            sb.append(handleHeader(requestHeaders, true)).append(NEWLINE);
            // 打印请求内容
    //        if (!request.method().toLowerCase().contains("get")) {
            RequestBody rb = request.body();
            if (rb != null) {
                okio.Buffer buffer = new okio.Buffer();
                rb.writeTo(buffer);
                sb.append("请求的数据为:").append(buffer.readUtf8()).append(NEWLINE);
                buffer.clear();
            }
    //        }
    
            Response response = chain.proceed(request);
            // 打印返回的header
            Headers responseHeaders = response.headers();
            sb.append(handleHeader(responseHeaders, false)).append(NEWLINE);
            // 打印返回内容
            String content = response.body().string();
            long responseTime = System.currentTimeMillis();
            sb.append("HTTP状态码:").append(response.code()).append(NEWLINE);
            sb.append("耗费时间为:").append(responseTime - requestTime).append("ms").append(NEWLINE);
            sb.append("返回的数据为:").append(content).append(NEWLINE);
            NetworkLogger.d(sb.toString());
            MediaType mediaType = response.body().contentType();
            return response.newBuilder().body(ResponseBody.create(mediaType, content)).build();
        }
    
        private String handleHeader(Headers headers, boolean isRequest) {
            Iterator<String> iterator = headers.names().iterator();
            StringBuilder headerString = new StringBuilder();
            headerString.append(isRequest ? "请求的header为:" : "返回的header为:");
            while (iterator.hasNext()) {
                String name = iterator.next();
                List<String> headerValues = headers.values(name);
                headerString.append("[").append(name).append(":").append(headerValues.isEmpty() ? "" : headerValues.get(0)).append("]");
            }
            return headerString.toString();
        }
    }
    

    OkHttpStack将volley的网络传输层实现交由okhttp完成,最后返回apache的response

    public class OkHttpStack implements HttpStack {
    
        @Override
        public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
                throws IOException, AuthFailureError {
    
            String originUrl = request.getUrl();
            Uri uri = Uri.parse(originUrl);
    
            boolean isHttps = false;
            if (uri.getScheme().toLowerCase().equals("https")) {
                isHttps = true;
            }
    
            // 2017/12/8  可以单独给 一个请求设置超时时间,具体参考 单元测试
            int timeout = request.getRetryPolicy().getCurrentTimeout();
            if (timeout == DefaultRetryPolicy.DEFAULT_TIMEOUT_MS) {
                // 2017/12/8  如果这里时间等于 volley 的默认时间,那么不应该手动设置超时时间,应该用 OkHttp 全局的。
                timeout = -1;
            }
    
            OkHttpClient client = OkHttpHelper.getClient(isHttps, timeout);
            com.hyperion.networklib.okhttp3.Request.Builder requestBuilder = new com.hyperion.networklib.okhttp3.Request.Builder();
    
            // 解析请求中的header和默认携带的header和内存中的cookie
            parseRequestHeader(requestBuilder, request);
            // 解析请求的数据
            parseRequestBody(requestBuilder, request);
    
            // 交由okhttp执行网络传输层
            com.hyperion.networklib.okhttp3.Request okhttp3Request = requestBuilder.url(uri.toString()).build();
            Response okHttpResponse = client.newCall(okhttp3Request).execute();
    
            // 解析返回数据的状态码
            StatusLine responseStatus = new BasicStatusLine(
                    parseProtocol(okHttpResponse.protocol()),
                    okHttpResponse.code(),
                    okHttpResponse.message()
            );
            BasicHttpResponse response = new BasicHttpResponse(responseStatus);
            // 解析返回的header
            parseResponseHeader(response, okHttpResponse);
            // 解析返回的数据
            parseResponseBody(response, okHttpResponse);
    
            return response;
        }
    
    
        private void parseRequestHeader(com.hyperion.networklib.okhttp3.Request.Builder builder, Request<?> request)
                throws IOException, AuthFailureError {
            Map<String, String> headers = request.getHeaders();
            if (headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    builder.addHeader(entry.getKey(), entry.getValue());
                }
            }
        }
    
        private void parseRequestBody(com.hyperion.networklib.okhttp3.Request.Builder builder, Request<?> request)
                throws IOException, AuthFailureError {
            switch (request.getMethod()) {
                case Request.Method.DEPRECATED_GET_OR_POST:
                    builder.post(createGetBody(request));
                    break;
    
                case Request.Method.GET:
                    builder.get();
                    break;
    
                case Request.Method.DELETE:
                    builder.delete();
                    break;
    
                case Request.Method.POST:
                    RequestBody requestBody = createPostBody(request);
                    if (requestBody != null) {
                        builder.post(requestBody);
                    }
                    break;
    
                case Request.Method.PUT:
                    builder.put(createGetBody(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(createGetBody(request));
                    break;
    
                default:
                    throw new IllegalStateException("Unknown method type.");
            }
        }
    
        private RequestBody createGetBody(Request request)
                throws AuthFailureError {
            final byte[] body = request.getBody();
            return RequestBody.create(MediaType.parse(request.getBodyContentType()), body);
        }
    
        private RequestBody createPostBody(Request request) throws AuthFailureError {
            RequestBody requestBody = null;
            if (request instanceof BaseCustomJsonRequest) {
                BaseCustomJsonRequest customJsonRequest = (BaseCustomJsonRequest) request;
                requestBody = customJsonRequest.getRequestBody();
            }else{
                requestBody = RequestBody.create(MediaType.parse(request.getBodyContentType()), request.getBody());
            }
            return requestBody;
        }
    
        private ProtocolVersion parseProtocol(final Protocol protocol) {
            switch (protocol) {
                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 void parseResponseHeader(BasicHttpResponse httpResponse, Response response) {
            Headers responseHeaders = response.headers();
            if (responseHeaders != null) {
                for (int i = 0, len = responseHeaders.size(); i < len; i++) {
                    final String name = responseHeaders.name(i);
                    final String value = responseHeaders.value(i);
                    if (name != null) {
                        httpResponse.addHeader(new BasicHeader(name, value));
                    }
                }
            }
        }
    
        private void parseResponseBody(BasicHttpResponse httpResponse, Response response) throws IOException {
            BasicHttpEntity entity = new BasicHttpEntity();
            ResponseBody body = response.body();
            entity.setContentLength(body.contentLength());
    
            String encoding = response.header("Content-Encoding");
            if (!TextUtils.isEmpty(encoding) && encoding.equals("gzip")) {
                entity.setContent(new GZIPInputStream(body.byteStream()));
            } else {
                entity.setContent(body.byteStream());
            }
            entity.setContentEncoding(encoding);
    
            if (body.contentType() != null) {
                entity.setContentType(body.contentType().type());
            }
            httpResponse.setEntity(entity);
        }
    
    }
    

    BaseCustomJsonRequest封装的兼容form和json请求

    /**
     * 封装的即可传递json,也可传递form
     */
    public abstract class BaseCustomJsonRequest<T> extends JsonRequest<T> {
    
        private Map<String, String> formBody;
        private Map<String, String> headers;
        private Charset charset = Charset.UTF8;
    
        /**
         * 请求json数据
         */
        public BaseCustomJsonRequest(int method, String url, String requestBody,
                                     Listener<T> listener, ErrorListener errorListener) {
            super(method, url, requestBody, listener, errorListener);
        }
    
        /**
         * 请求表单数据
         */
        public BaseCustomJsonRequest(int method, String url, Map<String, String> requestMap,
                                     Listener<T> listener, ErrorListener errorListener) {
            super(method, url, "", listener, errorListener);
            formBody = requestMap;
        }
    
        public Map<String, String> getFormBody() {
            return formBody;
        }
    
        public void setFormBody(Map<String, String> formBody) {
            this.formBody = formBody;
        }
    
        public Charset getCharset() {
            return charset;
        }
    
        public void setCharset(Charset charset) {
            this.charset = charset;
        }
    
        public void setHeaders(Map<String, String> headers) {
            this.headers = headers;
        }
    
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            if (headers == null || headers.isEmpty()) {
                headers = new HashMap<>();
            }
            headers.putAll(HeaderUtil.getRequestHeader(this));
            return headers;
        }
    
        public RequestBody getRequestBody() throws AuthFailureError {
            RequestBody bodyRes = null;
            Map<String, String> postBody = getFormBody();
            //在使用CustomJsonRequest的时候,如果设置了postBody,那么就直接从map取值,否则,使用json字符串方式
            if (postBody == null) {
                final byte[] body = getBody();
                if (body == null) return null;
                CustomJsonBody.Builder jsonBuilder = new CustomJsonBody.Builder();
                String bodyStr = null;
                try {
                    BaseCustomJsonRequest.Charset set = getCharset();
                    bodyStr = new String(body, BaseCustomJsonRequest.Charset.UTF8.getValue());
                    jsonBuilder.setRequstBodyCharset(set);
                    jsonBuilder.setJson(bodyStr);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
    
                bodyRes = jsonBuilder.build();
            } else {
                FormBody.Builder formBodyBuilder = new FormBody.Builder();
                for (Map.Entry<String, String> entry : postBody.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (value != null) {
                        formBodyBuilder.add(key, value);
                    }
                }
                bodyRes = formBodyBuilder.build();
            }
            return bodyRes;
        }
    
        public enum Charset {
    
            UTF8("UTF-8"),
            ISO("ISO-8859-1");
    
            String value;
    
            Charset(String value) {
                this.value = value;
            }
    
            public String getValue() {
                return value;
            }
        }
    }
    

    NetworkManager实现网络库的初始化以及添加一个新的网络请求

    public class NetworkManager {
    
        private volatile static NetworkManager instance;
    
        private Context mContext;
        private NetworkConfig mNetworkConfig;
        private HeaderStorage headerStorage;
        private CookieStorage cookieStorage;
        private CustomDiskCache diskCache;
        private RequestQueue requestQueue;
    
        private NetworkManager() {
            cookieStorage = new CookieStorage();
            headerStorage = new HeaderStorage(cookieStorage);
        }
    
        public static NetworkManager getInstance() {
            if (instance == null) {
                synchronized (NetworkManager.class) {
                    if (instance == null) {
                        instance = new NetworkManager();
                    }
                }
            }
            return instance;
        }
    
        public Context getContext() {
            return mContext;
        }
    
        public NetworkConfig getNetworkConfig() {
            return mNetworkConfig;
        }
    
        public HeaderStorage getHeaderStorage() {
            return headerStorage;
        }
    
        public CookieStorage getCookieStorage() {
            return cookieStorage;
        }
    
        public CustomDiskCache getDiskCache() {
            return diskCache;
        }
    
        public void init(Context context, NetworkConfig config) {
            if (context == null) {
                throw new IllegalStateException("Context cannot be null");
            }
            mContext = context.getApplicationContext();
            mNetworkConfig = config;
            if (mNetworkConfig == null) {
                mNetworkConfig = new NetworkConfig();
            }
    
            clearStorage();
            setHeaders(mNetworkConfig.getHeader());
    
            diskCache = new CustomDiskCache();
            OkHttpStack httpStack = new OkHttpStack();
            BasicNetwork network = new BasicNetwork(httpStack);
            requestQueue = new RequestQueue(diskCache.getBasedCache(), network, mNetworkConfig.getWorkerNumber());
            requestQueue.start();
        }
    
        public void clearStorage() {
            headerStorage.clear();
            cookieStorage.clear();
        }
    
        private void clearDisk() {
            ClearCacheRequest ccr = new ClearCacheRequest(diskCache.getBasedCache(), new Runnable() {
                @Override
                public void run() {
    
                }
            });
            requestQueue.add(ccr);
        }
    
        public void setHeaders(@NonNull Map<String, String> headers) {
            headerStorage.setHeaders(headers, true);
        }
    
        public void addHeaders(@NonNull Map<String, String> headers) {
            headerStorage.setHeaders(headers, false);
        }
    
        public Map<String, String> getHeaders() {
            return headerStorage.getHeaders();
        }
    
        public void updateCookie(Map<String, String> cookies) {
            cookieStorage.updateCookies(cookies);
        }
    
        public void addCookie(@NonNull String key, @NonNull String value) {
            cookieStorage.updateCookie(key, value);
        }
    
        public Map<String, String> getCookies() {
            return cookieStorage.getCookies();
        }
    
        public void cancel(@Nullable Object tag) {
            if (requestQueue != null) {
                requestQueue.cancelAll(tag);
            }
        }
    
        public void cancel(@NonNull RequestQueue.RequestFilter filter) {
            if (requestQueue != null) {
                requestQueue.cancelAll(filter);
            }
        }
    
        public void add(@NonNull Request req) {
            if (mContext == null) {
                throw new IllegalStateException("must invoke init method first");
            }
    
            //检查一下URL部分
            Uri uri = null;
            try {
                uri = Uri.parse(req.getUrl());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            if (uri == null) {
                NetworkLogger.e("the uri of request is Empty");
                return;
            }
    
            //检查一下是否是从允许的request中集成进来的
            if (!(req instanceof BaseCustomJsonRequest) && mNetworkConfig.isMustSpecifiedRequest()) {
                NetworkLogger.e("must add a BaseCustomJsonRequest");
                return;
            }
    
            String scheme = uri.getScheme().toLowerCase();
            if (!scheme.equals("https") && !scheme.equals("http")) {
                NetworkLogger.e("only support http or https");
                return;
            }
    
            RetryPolicy rp = req.getRetryPolicy();
            if (rp == null || (rp instanceof DefaultRetryPolicy && rp.getCurrentTimeout() ==
                    DefaultRetryPolicy.DEFAULT_TIMEOUT_MS && rp.getCurrentRetryCount() ==
                    DefaultRetryPolicy.DEFAULT_MAX_RETRIES)) {
                //如果没有自定义的RP,那么就使用默认的处理
                req.setRetryPolicy(new CustomRetryPolicy());
            }
            requestQueue.add(req);
        }
    
        /**
         * 检查网络是否可用
         *
         * @return true:可用;false:不可用
         */
        public boolean checkNetworkAvaiable() {
            if (mContext == null) {
                throw new IllegalStateException("must invoke init method first");
            }
            ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService
                    (Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo == null) {
                return false;
            }
            return networkInfo.isAvailable();
        }
    }
    

    5. 对okhttp源码的修改

    okhttp的源码给了三个目录

    • java:存放源代码的目录,但是缺一个Version类
    • java-templates:存放上面所缺的Version类
    • resources:存放域名检查相关的附件

    第一个改动,将java-templates目录下的Version类,放入源码的okhttp3.internal目录下,并稍加改动,主要就是指定okhttp3的版本。版本从github主页上找,当前我的版本是3.11.0

    public final class Version {
      public static String userAgent() {
        //return "okhttp/${project.version}";
        return "okhttp/3.11.0";
      }
    
      private Version() {
      }
    }
    

    第二个改动,将resources下的okhttp3.pro文件内容复制到当前module的proguard-rules.pro

    # JSR 305 annotations are for embedding nullability information.
    -dontwarn javax.annotation.**
    
    # A resource is loaded with a relative path so the package of this class must be preserved.
    -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
    
    # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
    -dontwarn org.codehaus.mojo.animal_sniffer.*
    
    # OkHttp platform used only on JVM and when Conscrypt dependency is available.
    -dontwarn okhttp3.internal.platform.ConscryptPlatform
    

    第三个改动,将resources下的publicsuffixes.gz文件放入assets下,并且重命名为publicsuffixes(否则会出现FileNotFoundException),然后找到PublicSuffixDatabase类,改动两处代码。为了适配okhttp在android上读取附件的功能

    // public static final String PUBLIC_SUFFIX_RESOURCE = "src/publicsuffixes.gz";
    public static final String PUBLIC_SUFFIX_RESOURCE = "publicsuffixes";
    
    // InputStream resource = PublicSuffixDatabase.class.getResourceAsStream(PUBLIC_SUFFIX_RESOURCE);
    InputStream resource = NetworkManager.getInstance().getContext().getAssets().open(PUBLIC_SUFFIX_RESOURCE);
    

    第四个改动,由于有些接口返回的domain和url不匹配导致接口会进行校验,此时加了一个配置开关forceIgnoredomain,可以强制不检验domain

    // cc 强制忽略域名检查
    boolean forceIgnoredomain = NetworkManager.getInstance().getNetworkConfig().isForceIgnoreCookieDomainCheck();
    // If the domain is present, it must domain match. Otherwise we have a host-only cookie.
    String urlHost = url.host();
    if (domain == null) {
        domain = urlHost;
    } else if (!forceIgnoredomain && !domainMatch(urlHost, domain)) {
        return null; // No domain match? This is either incompetence or malice!
    }
    
    // If the domain is a suffix of the url host, it must not be a public suffix.
    if (!forceIgnoredomain) {
        if (urlHost.length() != domain.length()
                && PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain) == null) {
            return null;
        }
    }
    

    6. 使用

    首先在Application中进行初始化

    private void initNetworkModule(){
        Map<String, String> headers = new HashMap<>();
        headers.put("time", System.currentTimeMillis() + "");
        headers.put("flatform", "android");
        NetworkConfig config = NetworkConfig.newBuilder()
                .setConnTimeout(10 * 1000)
                .setReadTimeout(10 * 1000)
                .setWriteTimeout(10 * 1000)
                .setCookieDomain("yourdomain.com")
                .setDeleteCookieKey("deleted")
                .setWorkerNumber(8)
                .setDebug(true)
                .setDiskCachePath("networklibcache")
                .setDiskCacheSize(1024 * 1024)
                .setMustSpecifiedRequest(false)
                .setLogTag("NetworkManager")
                .setHeader(headers)
                .setForceIgnoreCookieDomainCheck(true)
                .build();
        NetworkManager.getInstance().init(this, config);
    }
    

    然后分别请求form表格数据格式的请求和json数据格式的请求和GET请求

    private void testJsonParamRequest() {
        String url = "http://www.yourdomain.com/jmconnection/connection.php";
        JSONObject obj = new JSONObject();
        try {
            obj.put("ab", "11%3Ahide%7C701%3Ashow%7C801%3Ashow%7C901%3Ashow");
            obj.put("antifraud_sign", "58420247a79d7937aa92c936b9bf1200");
            obj.put("antifraud_tid", "1134814405");
        } catch (JSONException ex) {
            ex.printStackTrace();
        }
        BaseCustomJsonRequest request = new CustomJsonObjectRequest(Request.Method.POST, url, obj.toString(),
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        setText(response.toString());
                        Toast.makeText(MainActivity.this, "请求成功", Toast.LENGTH_SHORT).show();
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
                    }
                }
        );
        NetworkManager.getInstance().add(request);
    }
    
    private void testFormParamRequest() {
        int method = Request.Method.POST;
        String url = "https://www.yourdomain.com/v1/common/dynamic";
        HashMap<String, String> obj = new HashMap<>();
        obj.put("platform", "android");
        obj.put("source", "p-baidu-ppzq-bt");
        obj.put("site", "bj");
    
        CustomJsonObjectRequest hr = new CustomJsonObjectRequest(method, url, obj, new Response
                .Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                setText(response.toString());
                Toast.makeText(MainActivity.this, "请求成功", Toast.LENGTH_SHORT).show();
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
            }
        });
        NetworkManager.getInstance().add(hr);
    }
    
    private void testGetRequest() {
        int method = Request.Method.GET;
        String url = "https://suggest.taobao.com/sug?code=utf-8&q=车载";
        HashMap<String, String> obj = new HashMap<>();
    
        CustomJsonObjectRequest hr = new CustomJsonObjectRequest(method, url, obj, new Response
                .Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                setText(response.toString());
                Toast.makeText(MainActivity.this, "请求成功", Toast.LENGTH_SHORT).show();
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
            }
        });
        NetworkManager.getInstance().add(hr);
    }
    

    相关文章

      网友评论

          本文标题:Android:封装网络请求库Volley结合Okhttp

          本文链接:https://www.haomeiwen.com/subject/higwgftx.html