zoukankan      html  css  js  c++  java
  • android网络开源框架volley(五岁以下儿童)——volley一些细节

        最近的一次volley整理出下一个。我以前没有再次遭遇了一些小问题,在该记录:


    1、HttpUrlConnection DELETE 信息不能加入body问题:java.net.ProtocolException: DELETE does not support writing


        这个能够算是一个系统级的bug,为什么这么说,请看这里,这个问题在java8中才得以解决。没办法直接过去,咱就绕过去。查看HttpUrlConnection,我们发现他是一个抽象类,因此能够试试能不能通过它的其它实现来达到我们的目的。

    终于我们决定使用okhttp这个实现。地址为:https://github.com/square/okhttp

    接着我们还得去看看volley的源代码,因为我们的app兼容的最低版本号是4.0。因此我们知道终于调用的是HurlStack:

        public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
    ...
            if (stack == null) {
                if (Build.VERSION.SDK_INT >= 9) {
                    stack = new HurlStack();
                } else {
                    // Prior to Gingerbread, HttpUrlConnection was unreliable.
                    // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                    stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
                }
            }
    ...
        }

    因此我们仅仅须要将HurlStack的相关代码改动就可以,例如以下:

    volley.java

    public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
    ...
            if (stack == null) {
                if (Build.VERSION.SDK_INT >= 9) {
                    // old way: stack = new HurlStack();
                		// http://square.github.io/okhttp/
                    stack = new HurlStack(null, null, new OkUrlFactory(new OkHttpClient()));
                } else {
                    // Prior to Gingerbread, HttpUrlConnection was unreliable.
                    // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                    stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
                }
            }
    ...
        }
    HurlStack.java

    /**
     * An {@link HttpStack} based on {@link HttpURLConnection}.
     */
    public class HurlStack implements HttpStack {
    
        private final OkUrlFactory mOkUrlFactory; 
    
        /**
         * @param urlRewriter Rewriter to use for request URLs
         * @param sslSocketFactory SSL factory to use for HTTPS connections
         * @param okUrlFactory solution delete body(https://github.com/square/okhttp)
         */
        public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory, OkUrlFactory okUrlFactory) {
            mUrlRewriter = urlRewriter;
            mSslSocketFactory = sslSocketFactory;
            mOkUrlFactory = okUrlFactory;
        }
        /**
         * Create an {@link HttpURLConnection} for the specified {@code url}.
         */
        protected HttpURLConnection createConnection(URL url) throws IOException {
    		if(null != mOkUrlFactory){
    			return mOkUrlFactory.open(url);
    		}
            return (HttpURLConnection) url.openConnection();
        }
    
    
        @SuppressWarnings("deprecation")
        /* package */ 
        static void setConnectionParametersForRequest(HttpURLConnection connection,
                Request<?

    > request) throws IOException, AuthFailureError { switch (request.getMethod()) { ... case Method.DELETE: connection.setRequestMethod("DELETE"); addBodyIfExists(connection, request); break; ... default: throw new IllegalStateException("Unknown method type."); } } ... }


    2015-04-26更新:

    再次使用到须要使用到okhttp,回头看下上面的代码,不知道当时怎么想的。使用这么复杂的方法引入Okhttp。预计是脑袋进水了。

    再来看下这种方法:newRequestQueue(Context context, HttpStack stack),有两个參数:context和HttpStack,这里是要传入自己的HttpStack就好了。

    那么我们用OKhttp的实现:

    /**
     * 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);
      }   
    }
    參考:https://gist.github.com/JakeWharton/5616899

    2、关于(改动)volley的缓存


        volley有完整的一套缓存机制。而眼下我们想做个简单的需求:部分界面(差点儿不会改动的)简单的做一定时间的缓存,研究了下代码发现非常easy改动达到自己的目的(有时间在分析下volley的缓存机制,这个一定要做)。简单来说改动一个地方:request.parseNetworkResponse中的

    HttpHeaderParser(此处突然感慨volley的设计TMD灵活了。想怎么改就怎么改)。HttpHeaderParser改动后的代码例如以下:

    /**
     * 改动后的。用户处理缓存
     */
    public class BHHttpHeaderParser {
    
        /**
         * Extracts a {@link Cache.Entry} from a {@link NetworkResponse}.
         *
         * @param response The network response to parse headers from
         * @return a cache entry for the given response, or null if the response is not cacheable.
         */
        public static Cache.Entry parseCacheHeaders(NetworkResponse response, boolean isCustomCache) {
    ...
            if(isCustomCache){
            		softExpire = now + Config.HTTP_CACHE_TTL;
            } else {
    	        	if (hasCacheControl) {
    	            softExpire = now + maxAge * 1000;
    	        } else if (serverDate > 0 && serverExpires >= serverDate) {
    	            // Default semantic for Expire header in HTTP specification is softExpire.
    	            softExpire = now + (serverExpires - serverDate);
    	        }
            }
            
            Cache.Entry entry = new Cache.Entry();
            entry.data = response.data;
            entry.etag = serverEtag;
            entry.softTtl = softExpire;
            entry.ttl = entry.softTtl;
            entry.serverDate = serverDate;
            entry.responseHeaders = headers;
    
            return entry;
        }
    ...
    }

    此处大家能够发现,我们主要是依据自己定义的变量决定怎样改动cache的TTL来达到自己的目的。


    3、HttpUrlConnection与PATCH(2015-04-26)


    在使用Volley发送PATCH请求的时候,我们可能会遇到这种问题:Unknown method 'PATCH'; must be one of [OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE]。这个时候你的第一反应是什么呢?是Volley不支持PATCH请求吗?换成OkHttp是不是能够呢?查看了下Volley的源代码,在HurlHttp.java中发现例如以下一段:

    /* package */ 
    static void setConnectionParametersForRequest(HttpURLConnection connection,
                Request<?> request) throws IOException, AuthFailureError {
            switch (request.getMethod()) {
                case 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.
                        connection.setDoOutput(true);
                        connection.setRequestMethod("POST");
                        connection.addRequestProperty(HEADER_CONTENT_TYPE,
                                request.getPostBodyContentType());
                        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                        out.write(postBody);
                        out.close();
                    }
                    break;
                case Method.GET:
                    // Not necessary to set the request method because connection defaults to GET but
                    // being explicit here.
                    connection.setRequestMethod("GET");
                    break;
                case Method.DELETE:
                    connection.setRequestMethod("DELETE");
                    break;
                case Method.POST:
                    connection.setRequestMethod("POST");
                    addBodyIfExists(connection, request);
                    break;
                case Method.PUT:
                    connection.setRequestMethod("PUT");
                    addBodyIfExists(connection, request);
                    break;
                case Method.HEAD:
                    connection.setRequestMethod("HEAD");
                    break;
                case Method.OPTIONS:
                    connection.setRequestMethod("OPTIONS");
                    break;
                case Method.TRACE:
                    connection.setRequestMethod("TRACE");
                    break;
                case Method.PATCH:
                    connection.setRequestMethod("PATCH");
                    addBodyIfExists(connection, request);
                    break;
                default:
                    throw new IllegalStateException("Unknown method type.");
            }
        }
    通过这段代码。我们知道,Volley对PATCH还是支持的。在细看下错误这个是有HttpUrlConnection抛出的。因此我们须要在这方面下手。

    这里有一个參考:

    https://github.com/adriancole/retrofit/commit/e704b800878b2e37f5ac98b0139cb4994618ace0



    以后有其它关于volley它被记录在这个摘要。


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    原生微信小程序砸金蛋奖程序代码分析
    git 如何恢复到指定版本--很常用的方法
    cupload.js手动插入数据
    asp.net Core3.1自定义权限体系-菜单和操作按钮权限
    linux 解决docker、docker-compose命令权限问题(sudo)
    Supervisor 安装和使用教程
    php 无限级分类查找父节点所有子节点【找出 某节点的子节点】
    bat echo 输出内容为不同的颜色
    git 提交团队项目代码的流程
    bat脚本 切换到其他盘符
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4805450.html
Copyright © 2011-2022 走看看