Volley框架的理解以及自定义各个对象

Volley框架的基本流程就是:


我们在代码中RequestQueuequeue 是这样写的:

StringRequestrequest = new StringRequest(URL, new Response.Listener<String>() {
 
      @Override
      public void onResponse(String s) {
          System.out.println("onResponse:"+s);
      }
  }, new Response.ErrorListener() {
      @Override
      public void onErrorResponse(VolleyErrorvolleyError) {
          System.out.println("onErrorResponse: " +volleyError);
      }
  });
  request.setTag(toString());
 
  RequestQueuequeue = Volley.newRequestQueue(this);
  queue.add(request);


第一步:新建一个XXXrequest,参数自己定义,第一个参数是url,第二个是返回正确的处理函数,第三个是错误处理函数;XXXrequest有很多种构造函数,这只是其中的一.
第二步新建:RequestQueuequeue对象,构造函数的有两个,一个是只需要context,一个是context以及httpstack参数,第二个构造函数需要我们自己定义httpstack(这个我们后面讲)

第三步将XXXrequest加入到requestQueue中。 


看起来我们什么都没有做,却能请求道我们需要的数据,这是因为volley内部已经自动完成所有的操作。接下来我就要说说volley的执行流程,RequestQueue新建出来后,就会在RequestQueue里面创建一个CacheQueue,和一个NetworkQueue,然后创建一个Thread1(CacheDIspatcher),三个Thread2(NetworkDispatcher), CacheDispatcher不断轮询RequestQueue,  把队列里面能在内存缓存中找到的资源的请求加入到CacheQueue队列中,如果内存资源不能找到,CacheDispatcher中会将请求加入到NetworkQueue网络资源队列中,这样就有了两个队列了,内存缓存的处理以后再说,先说下网络请求缓存,有队列后Thread2就会轮询NetworkQueue,将请求取出来交由Network处理,network又是有Httpstack初始化的,HttpStack又会基于当前API版本生成HttpUrlconection或者HttpClient,网络请求结束后就会调用各种回调,使用UI的handle将回调发送到主线程中,最终回到主UI线程处理视图。

其中XXXrequest的需要@Overwrite函数有以下这几个
//这个函数是回调给主线程数据用的
protected void deliverResponse(T response) {
    this.mListener.onResponse(response);
}


//该函数是解析从服务器返回的数据用的,解析JSON,String,Bitmap等等,自定义XXXRequest就是改写这个函数
protected abstract Response<T> parseNetworkResponse(NetworkResponse var1);


/** @deprecated 改写请求Body部分的函数*/
public String getPostBodyContentType() {
    return this.getBodyContentType();
}


/** @deprecated */
public byte[] getPostBody() {
    return this.getBody();
}


public String getBodyContentType() {
    return PROTOCOL_CONTENT_TYPE;
}


public byte[] getBody() {}


//下面这个函数非常重要,这个函数是用来改写请求的Header部分用的。自定义XXXRequest中需要改写此函数,
public byte[] getHeader() {}

从上面的XXXRequest的父类函数中根本没有看到任何Http请求的对象,那么Volley的网络 请求时怎么进行的呢?这就要去看源码了,从源码来看的话,

public interface Network {
    NetworkResponse performRequest(Request<?> var1) throws VolleyError;
}
有这样一个接口需要我们去实现。
而在NetworkDispatcher函数中,

public class NetworkDispatcher extends Thread {
public NetworkDispatcher(BlockingQueue<Request<?>> queue, Network network, Cache cache, 
ResponseDelivery delivery) {
    this.mQueue = queue;
    this.mNetwork = network;
    this.mCache = cache;
    this.mDelivery = delivery;
}
public void run() {
	
	.
	.
	.

    Process.setThreadPriority(10);


    while(true) {
          NetworkResponse e = this.mNetwork.performRequest(request);
    }
}

从NetworkDispatcher看的出来这个类需要network初始化,在调用performRequest的时候就会使用Request<T>参数,一个Network对象就会在该函数里面组装头部,body部分,然后执行请求等等;我们要注意搞清楚这个关系:
network的子类实现是BasicNetwork,
BasicNetwork的构造函数的参数有HttpStack,
HttpStack的对象里面是分为HttpUrlconnnection,HttpClient的作为请求对象的(根据当前的API水平)



而最终是由NetworkDispatcher(是个子线程)调用network.performRequest(XXXRequest<T> val),在此函数中编辑HttpStack的header和body,至于怎么调用,因为XXXRequest里面的@overwrite函数都可以得到各种参数,对于httpconnection的各种参数设置,超时时间以及是否支持缓存和缓存时间,这个是在HttpStack初始化请求对象的时候可以设置。
然后,network的子类在Volley的实现是BasicNetwork类,在构建这个对象的时候,一个HttpStack对象去传给它作为参数,而它将会调用这个HttpStack去获取事情。它是对HttpUrlConnection和HttpClient的一个包装,让外面的对象不用去关心到底是通过哪个接口来获取数据。

NetworkResponse performRequest(Request<?> var1) throws VolleyError;
从上面的分析可以得出,有哪些有自定义的必要呢?第一XXXRequest有必要自己定义,可以定义请求的返回的类型,第二HttpStack有必要自己定义,可以定义请求对象的类型是HttpUrlconnection,还是HttpClient,还是最新最潮流的OKHttpCliet呢?自己看着办,而且也可以在这里判断是否需要缓存服务器的数据,分析header部分   和body部分。第三Cache,这个可以自己定义,在这里面,与DisCache直接关联,需不需要磁盘缓存,内存的数据多久向磁盘中缓存,也可以使用其他的缓存策略等等。第四自定义RequestQueues,在这里重写各个处理线程的个数。

比如下面这个,重写Request<T>,头部改写
 
RequestQueue queue = Volley.newRequestQueue(this); String url = "http://www.somewebsite.com";
   StringRequest postRequest = new StringRequest(Request.Method.GET, url, 
new Response.Listener<String>() 
        {
            @Override
            public void onResponse(String response) {
                // response
                Log.d("Response", response);
            }
        }, 
        new Response.ErrorListener() 
        {
            @Override
            public void onErrorResponse(VolleyError error) {
                // TODO Auto-generated method stub
                Log.d("ERROR","error => "+error.toString());
            }
        }
    ) {     
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError { 
                Map<String, String>  params = new HashMap<String, String>();  
                params.put("User-Agent", "Nintendo Gameboy");  
                params.put("Accept-Language", "fr");


                return params;  
        }
    };
    queue.add(postRequest);

 比如下面这个改写HttpStack:使用最新的OKHttpClient作为最底层的网络请求对象。

/**集成最新OKHttpClient;
 * 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);
  }   
}


public class OkHttpStack implements HttpStack
{
    private final OkHttpClient mClient;


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


    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError
    {
        OkHttpClient client = mClient.clone();
        int timeoutMs = request.getTimeoutMs();
        client.setConnectTimeout(timeoutMs, TimeUnit.MILLISECONDS);
        client.setReadTimeout(timeoutMs, TimeUnit.MILLISECONDS);
        client.setWriteTimeout(timeoutMs, TimeUnit.MILLISECONDS);


        com.squareup.okhttp.Request.Builder okHttpRequestBuilder =
                new com.squareup.okhttp.Request.Builder();
        okHttpRequestBuilder.url(request.getUrl());


        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);


        com.squareup.okhttp.Request okHttpRequest = okHttpRequestBuilder.build();
        Call okHttpCall = client.newCall(okHttpRequest);
        Response okHttpResponse = okHttpCall.execute();


        StatusLine responseStatus = new BasicStatusLine
                (
                        parseProtocol(okHttpResponse.protocol()),
                        okHttpResponse.code(),
                        okHttpResponse.message()
                );


        BasicHttpResponse response = new BasicHttpResponse(responseStatus);
        response.setEntity(entityFromOkHttpResponse(okHttpResponse));


        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) throws IOException
    {
        BasicHttpEntity entity = new BasicHttpEntity();
        ResponseBody body = r.body();


        entity.setContent(body.byteStream());
        entity.setContentLength(body.contentLength());
        entity.setContentEncoding(r.header("Content-Encoding"));


        if (body.contentType() != null)
        {
            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:
                // Ensure backwards compatibility.
                // Volley assumes a request with a null body is a GET.
                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.");
        }
    }


    private static 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);
            case HTTP_2:
                return new ProtocolVersion("HTTP", 2, 0);
        }


        throw new IllegalAccessError("Unkwown protocol");
    }


    private static RequestBody createRequestBody(Request r) throws AuthFailureError
    {
        final byte[] body = r.getBody();
        if (body == null) return null;


        return RequestBody.create(MediaType.parse(r.getBodyContentType()), body);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值