转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/50888340
本文出自:【顾林海的博客】

##前言
Volley这个网络框架大家并不陌生,它的优点网上一大堆, 适合网络通信频繁操作,并能同时实现多个网络通信、扩展性强、通过接口配置之类的优点。在写这篇文章之前,特意去了解并使用Volley这个网络框架,文章是对Volley的一点点理解,如有写得不到位的地方,欢迎大家指出。

##用法
使用Volley的通用步骤就是通过Volley暴露的newRequestQueue方法,创建的我们的RequestQueue,接着往我们的RequestQueue中添加Request( StringRequest、JsonRequest、ImageRequest,以及你自己定义的Request)。

private void initNetWork() {RequestQueue queue = Volley.newRequestQueue(this);String url = "";StringRequest stringRequest = new StringRequest(Request.Method.GET,url, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {}});queue.add(stringRequest);queue.start();}

步骤很简单,总结就三步:

  1. 创建一个RequestQueue对象。
  2. 创建一个StringRequest对象。
  3. 将StringRequest对象添加到RequestQueue里面。

上面的实例通过get方式请求数据的,post的方式也是很简单,在创建Request的时候,第一个参数改为Request.Methode.POST:

private void initNetWork_1() {RequestQueue queue = Volley.newRequestQueue(this);String url = "";StringRequest stringRequest = new StringRequest(Request.Method.POST,url, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {}}) {@Overrideprotected Map<String, String> getParams() throws AuthFailureError {// TODO Auto-generated method stubreturn super.getParams();}};queue.add(stringRequest);queue.start();
}

仔细查看上面POST和GET的不同方式的请求代码,可以看出POST的时候多了一个getParams方法,返回的Map类型,getParams获取的数据是用于向服务器提交的参数。
在这里我们看到,如果每次都去定义Map,然后往里面put键值对,这是一件很沮丧的事情,这里给出一个工具类,可以通过解析对象转换成我们需要的Map,代码如下:

package com.example.volleyproject;import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;public class MapUtil {public static <T> Map<String, String> changeTtoMap(T m) {HashMap<String, String> map = new HashMap<String, String>();// 获取实体类的所有属性Field[] field = m.getClass().getDeclaredFields();// 遍历所有属性for (int j = 0; j < field.length; j++) {// 获取属性的名字String name = field[j].getName();String value = (String) getFieldValueObj(m, name);if (value != null && !value.equals("")) {map.put(name, value);}}return map;}/*** 获取对应的属性值** @param target*            对象* @param fname*            Filed* @return*/public static Object getFieldValueObj(Object target, String fname) { // 获取字段值// 如:username 字段,getUsername()if (target == null || fname == null || "".equals(fname)) {// 如果类型不匹配,直接退出return "";}Class clazz = target.getClass();try { // 先通过getXxx()方法设置类属性值String methodname = "get" + Character.toUpperCase(fname.charAt(0))+ fname.substring(1);Method method = clazz.getDeclaredMethod(methodname); // 获取定义的方法if (!Modifier.isPublic(method.getModifiers())) { // 设置非共有方法权限method.setAccessible(true);}return (Object) method.invoke(target); // 执行方法回调} catch (Exception me) {// 如果get方法不存在,则直接设置类属性值try {Field field = clazz.getDeclaredField(fname); // 获取定义的类属性if (!Modifier.isPublic(field.getModifiers())) { // 设置非共有类属性权限field.setAccessible(true);}return (Object) field.get(target); // 获取类属性值} catch (Exception fe) {}}return "";}
}

最后在getParams 调用这个工具类中的changeTtoMap方法即可:

private void initNetWork_1() {RequestQueue queue = Volley.newRequestQueue(this);String url = "";final RequestParams params = new RequestParams();params.id = "1";params.name = "bill";StringRequest stringRequest = new StringRequest(Request.Method.POST,url, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {}}) {@Overrideprotected Map<String, String> getParams() throws AuthFailureError {return MapUtil.changeTtoMap(params);}};queue.add(stringRequest);queue.start();
}

##Volley的浅谈

所有操作都是基于上面讲的三个步骤,第一步创建一个RequestQueue对象。

RequestQueue queue = Volley.newRequestQueue(this);

请求队列(RequestQueue)不需要出现多个,因此我们可以在Application中进行初始化。

  /*** Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.** @param context A {@link Context} to use for creating the cache dir.* @return A started {@link RequestQueue} instance.*/public static RequestQueue newRequestQueue(Context context) {return newRequestQueue(context, null);}

方法很简单,创建的我们的请求队列,这里通过传入Context来确定我们缓存目录。

 /*** Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.** @param context A {@link Context} to use for creating the cache dir.* @param stack An {@link HttpStack} to use for the network, or null for default.* @return A started {@link RequestQueue} instance.*/public static RequestQueue newRequestQueue(Context context, HttpStack stack) {File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);String userAgent = "volley/0";try {String packageName = context.getPackageName();PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);userAgent = packageName + "/" + info.versionCode;} catch (NameNotFoundException e) {}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.htmlstack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));}}Network network = new BasicNetwork(stack);RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);queue.start();return queue;}

在Volley中,http的处理请求,默认 Android2.3 及以上基于 HttpURLConnection的 HurlStack,2.3 以下基于 HttpClient 的 HttpClientStack,通过上面的这段代码可知:

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.htmlstack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));}}

这里面的HurlStack和HttpClientStack都实现了HttpStack这个接口,HttpStack是用于http请求,返回请求结果的。

public interface HttpStack {/*** Performs an HTTP request with the given parameters.** <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,* and the Content-Type header is set to request.getPostBodyContentType().</p>** @param request the request to perform* @param additionalHeaders additional headers to be sent together with*         {@link Request#getHeaders()}* @return the HTTP response*/public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)throws IOException, AuthFailureError;}public class HttpClientStack implements HttpStack {
}public class HurlStack implements HttpStack{
}

在根据SDK版本确定使用哪个Http请求方式后创建BasicNetwork对象,BasicNetwork实现了Network接口:

/*** An interface for performing requests.*/
public interface Network {/*** Performs the specified request.* @param request Request to process* @return A {@link NetworkResponse} with data and caching metadata; will never be null* @throws VolleyError on errors*/public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}

NetWork用于 调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse。 这里面的BasicNetwork就是一个具体是实现。

接着执行:

RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();

DiskBasedCache是我们缓存的目录:

 public DiskBasedCache(File rootDirectory) {this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);}public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {mRootDirectory = rootDirectory;mMaxCacheSizeInBytes = maxCacheSizeInBytes;}

这里面定义了缓存的地址,默认最大是5MB。继续查看RequestQueue的构造器:

public RequestQueue(Cache cache, Network network) {this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);}public RequestQueue(Cache cache, Network network, int threadPoolSize) {this(cache, network, threadPoolSize,new ExecutorDelivery(new Handler(Looper.getMainLooper())));}public RequestQueue(Cache cache, Network network, int threadPoolSize,ResponseDelivery delivery) {mCache = cache;mNetwork = network;mDispatchers = new NetworkDispatcher[threadPoolSize];mDelivery = delivery;}

在创建RequestQueue实例时进行了一系列的初始化(缓存、HttpStack的处理请求、线程池大小、返回结果的分发)。
NetworkDispatcher是一个线程, 用于调度处理网络的请求。启动后会不断从网络请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理,并判断结果是否要进行缓存。

public class NetworkDispatcher extends Thread {
}

这里面的ResponseDelivery用于返回结果分发接口,目前只有基于ExecutorDelivery的 handler 对应线程内进行分发。

ExecutorDelivery通过内部的handler对应的线程进行返回结果的分发:

public ExecutorDelivery(final Handler handler) {// Make an Executor that just wraps the handler.mResponsePoster = new Executor() {@Overridepublic void execute(Runnable command) {handler.post(command);}};
}

Executor框架是java 5引入的并发库,把任务拆分为一些列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe) 。Executor在执行时使用内部的线程池完成操作。

这里面传递进来的是new Handler(Looper.getMainLooper()),传入UI线程的Handler的目的是用于UI更新,比如通过通过Volley进行图片下载时的ImageView更新。

上面也提到过ResponseDelivery用于返回结果分发,目前只基于ExecutorDelivery的handler对应线程进行分发,由此我们找到数据分发的方法:

 @Overridepublic void postResponse(Request<?> request, Response<?> response) {postResponse(request, response, null);}@Overridepublic void postResponse(Request<?> request, Response<?> response, Runnable runnable) {request.markDelivered();request.addMarker("post-response");mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));}@Overridepublic void postError(Request<?> request, VolleyError error) {request.addMarker("post-error");Response<?> response = Response.error(error);mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));}

在postResponse、postError都调用了Executor.execute(Runnalbe)方法进行并发执行,ResponseDeliveryRunnable实现了Runnable接口并重写run方法:

 public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {mRequest = request;mResponse = response;mRunnable = runnable;}@Overridepublic void run() {// If this request has canceled, finish it and don't deliver.if (mRequest.isCanceled()) {mRequest.finish("canceled-at-delivery");return;}// Deliver a normal response or error, depending.if (mResponse.isSuccess()) {mRequest.deliverResponse(mResponse.result);} else {mRequest.deliverError(mResponse.error);}// If this is an intermediate response, add a marker, otherwise we're done// and the request can be finished.if (mResponse.intermediate) {mRequest.addMarker("intermediate-response");} else {mRequest.finish("done");}// If we have been provided a post-delivery runnable, run it.if (mRunnable != null) {mRunnable.run();}}

run方法中的代码比较简单,进行数据的分发,这里面的mResponse就是我们返回的结果,通过mRequest.deliverResponse(mResponse.result);进行数据分发,这里面的Request是一个请求的抽象类,进入StringRequest类中,我们发现StringRequest实现了这个抽象类:

public class StringRequest extends Request<String>{
}

在StringRequest 中我们找到这么一段代码:

 @Overrideprotected void deliverResponse(String response) {mListener.onResponse(response);}

对比之前我们定义的StringRequest的代码:

StringRequest stringRequest = new StringRequest(Request.Method.GET,url, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {}});

是不是很熟悉,最后结果就是通过ExecutorDelivery中handler对应线程进行分发处理的。
到这里请求队列(RequestQueue)就初始化完毕了。
接着就是定义我们的Request,Volley定义了现成的Request,像 StringRequest、JsonRequest、ImageReques,当然我们可以根据StringRequest一样定义我们自己的Request,只需实现Request这个抽象类:

package com.android.volley.toolbox;import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;import java.io.UnsupportedEncodingException;/*** A canned request for retrieving the response body at a given URL as a String.*/
public class StringRequest extends Request<String> {private final Listener<String> mListener;/*** Creates a new request with the given method.** @param method the request {@link Method} to use* @param url URL to fetch the string at* @param listener Listener to receive the String response* @param errorListener Error listener, or null to ignore errors*/public StringRequest(int method, String url, Listener<String> listener,ErrorListener errorListener) {super(method, url, errorListener);mListener = listener;}/*** Creates a new GET request.** @param url URL to fetch the string at* @param listener Listener to receive the String response* @param errorListener Error listener, or null to ignore errors*/public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {this(Method.GET, url, listener, errorListener);}@Overrideprotected void deliverResponse(String response) {mListener.onResponse(response);}@Overrideprotected Response<String> parseNetworkResponse(NetworkResponse response) {String parsed;try {parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));} catch (UnsupportedEncodingException e) {parsed = new String(response.data);}return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));}
}

查看StringRequest源码,重写了以下两个方法:

abstract protected void deliverResponse(T response);
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);

NetworkResponse存放的是从服务器返回并以字节形式的数据。按照StringRequest我们可以定义GsonRequest:

public class GsonRequest<T> extends Request<T> {private final Listener<T> mListener;private Gson mGson;private Class<T> mClass;public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,ErrorListener errorListener) {super(method, url, errorListener);mGson = new Gson();mClass = clazz;mListener = listener;}public GsonRequest(String url, Class<T> clazz, Listener<T> listener,ErrorListener errorListener) {this(Method.GET, url, clazz, listener, errorListener);}@Overrideprotected Response<T> parseNetworkResponse(NetworkResponse response) {try {String jsonString = new String(response.data,HttpHeaderParser.parseCharset(response.headers));return Response.success(mGson.fromJson(jsonString, mClass),HttpHeaderParser.parseCacheHeaders(response));} catch (UnsupportedEncodingException e) {return Response.error(new ParseError(e));}}@Overrideprotected void deliverResponse(T response) {mListener.onResponse(response);}}

到这里为止我们的队列以及请求响应都已定义好,最后通过请求队列的start方法进行请求:

public void start() {stop();  // Make sure any currently running dispatchers are stopped.// Create the cache dispatcher and start it.mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);mCacheDispatcher.start();// Create network dispatchers (and corresponding threads) up to the pool size.for (int i = 0; i < mDispatchers.length; i++) {NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,mCache, mDelivery);mDispatchers[i] = networkDispatcher;networkDispatcher.start();}}public void stop() {if (mCacheDispatcher != null) {mCacheDispatcher.quit();}for (int i = 0; i < mDispatchers.length; i++) {if (mDispatchers[i] != null) {mDispatchers[i].quit();}}}CacheDispatcher和NetworkDispatcher中的quit方法:public void quit() {mQuit = true;interrupt();}

通过start方法对队列进行调度,方法中的先通过stop进行缓存和网络请求的调度终止,通过它们的quit方法中的interrupt方法进行线程中断,CacheDispatcher是 一个线程,用于调度处理走缓存的请求。启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery去执行后续处理。当结果未缓存过、缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理。
由此start方法中的处理逻辑就一目了然了,先是经过缓存的请求,在未缓存过或是缓存失效时,再进入网络的请求,并判断结果是否要进行缓存。

Android之对Volley网络框架的一些理解相关推荐

  1. 上门洗车APP --- Android客户端开发 之 网络框架封装介绍(一)

    上门洗车APP --- Android客户端开发 之 网络框架封装介绍(一) 上篇文章中给大家简单介绍了一些业务,上门洗车APP --- Android客户端开发 前言及业务简介,本篇文章给大家介绍下 ...

  2. Volley网络框架分享

    简 介 1 Volley是在2013年谷歌发布的一款快捷高效.轻量级的网络通信框架,里面封装了HttpURLConnection和HttpClient的通信细节. 2 优点: 自动调度网络请求: 非常 ...

  3. 云炬Android开发笔记 5-7网络框架优化与完善

    4.网络框架优化与完善 4.1[支持原始数据的post请求] 4.2[支持原始数据的putRaw] 4.3[增加UPLOAD上传方法] [会存在文件的传递]

  4. Android 网络编程系列(5)Volley 网络框架入门

    前言 上篇文章中我们对 HttpUrlConnection 的相关用法稍作介绍,可以看到如果不对它进行封装,那么每次使用时就必须写很多重复的代码,并且需要自己创建线程进行网络连接,获取到响应结果后还需 ...

  5. pre-network android预加载网络框架

    网络优化是所有app开发中非常重要的一部分,如果将网络请求前置就是在点击跳转activity之前开始网络加载那么速度将会有质的提升.也就是网络预先加载框框架. 网络预加载框架,监听式网络前置加载框架- ...

  6. Android 网络框架 Retrofit2.0介绍、使用和封装

    前言 时至今日,Android的网络框架不再像之前那么到处都是,随着Google把 HttpClient直接删掉,似乎意味着Android越来越成熟.网络框架中的佼佼者Volley也不再那么光鲜,取而 ...

  7. Android 开源网络框架OKHttp4 Kotlin版本源码解析

    Android 开源网络框架OKHttp 4 解析 文章目录 Android 开源网络框架OKHttp 4 解析 1.Http2.0协议主要增加的优化点: 2.OkHttp支持的内容 3.OkHttp ...

  8. Android网络框架Volley的快速使用

    一.基本使用 之前做Android开发都是使用学长自己封装好的网络请求框架,第三方网络框架也很多,网上搜索了一下,大多数人推荐使用 android-async-http okhttp Volley 其 ...

  9. ym—— Android网络框架Volley(终极篇)

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103).谢谢支持! 没看使用过Volley的同学能够,先看看 Android网络框架Volley(体验篇) ...

最新文章

  1. SQL 左连接(left join) 排序 分页 中遇到的未按理想状态排序分页的解决方案
  2. 在linux下给grep命令添加颜色
  3. 【STM32】利用 C 语言 strchar() 函数查找字符串中指定字符的位置
  4. 【JavaSE03】Java中分支语句-思维导图
  5. Bezier(贝塞尔)曲线的轨迹规划在自动驾驶中的应用(一)
  6. 计算机技师工作调研,技师学院党委书记王庆余到计算机工程系进行“不忘初心、牢记使命”主题教育调研工作...
  7. 201621123015《Java程序设计》第11周学习总结
  8. *.sln和*.suo文件的作用
  9. SQL SERVER中的二种获得自增长ID的方法
  10. jQuery学习: 实现select multiple左右添加和删除功能
  11. Linux Kernel 5.0 近日正式面向公众
  12. timerfd.h中定义的函数
  13. java中String类和StringBuffer类实例详解
  14. java手机编程软件_手机java编程软件下载
  15. 如何使用Axure制作产品需求文档prd
  16. eTerm放大/PID放大软件众多,如何选择
  17. 2020 不忘初心 继续前行
  18. STM32——EMWIN对话框(十二)
  19. java中的元音 辅音_元音辅音分类表
  20. ntoskrnl.exe文件丢失或损坏的问题解决方法

热门文章

  1. weblogic部署静态资源文件html,如何使用Spring的mvc提供静态资源:WebLogic上的资源?...
  2. win7下命令行提示符从C盘进入E盘的文件夹下
  3. spring boot的热加载(hotswap)
  4. Mybatis 通用 Mapper 使用 ①
  5. mac下的抓包工具Charles
  6. 算法模板——二分图匹配
  7. DFS分布式文件系统 不同用户访问不同服务器修改同一文件 解决方案
  8. CommandBehavior.CloseConnection有何作用
  9. Django 中ORM 的使用
  10. MySQL时间增加、字符串拼接