您的位置:首页 > 移动开发 > Android开发

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

2016-06-27 21:55 369 查看
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);
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  框架 android