· 自动调度网络请求
· 支持并发网络连接(即支持多线程)
· 支持标准的HTTP缓存协议(由服务器来决定是否缓存数据)
· 支持请求优先级设置(4级)
· 支持取消单个或多个请求
· 易于定制(重试),扩展性强。比如Retry&Backoff机制
· 强大的网络请求能力让你轻松的发送异步请求来填充UI数据
· 提供调试和跟踪工具
擅长将RPC(远程过程调用协议,C/S模式)类型的操作,用来展示服务器数据。比如以某种数据格式获取一页搜索结果。支持任意的数据传输格式,比如图片,字符串,json,你也可以定义自己的数据格式。其实就是自定义Request。Volley让你不再写这些重复的模板代码(网络请求逻辑,不再重复造轮子),这样你就可以专注于你应用本身的业务逻辑.
由于Volley都是在内存中解析和处理数据,所以不适合大数据量的下载操作。如果需要下载大文件,可以考虑使用系统的DownloadManager。
1. 直接把代码clone下来,把volley的代码直接copy到你的project里,
git clone https://android.googlesource.com/platform/frameworks/volley
2. 作为一个library项目存在或者jar包存在
3. 添加网络权限
1. 初始化一个RequestQueue
mRequestQueue = Volley.newRequestQueue(this);
2. 构建一个Request,这个Demo里我们使用的是StringRequest
StringRequest request = new StringRequest(
要访问的URL,
new Response.Listener
new Response.ErrorListener() {}); //请求结果错误返回的lisetner
3. 将Request对象添加到RequestQueue中
mRequestQueue.add(request);
当调用add()方法的时候,Volley会运行一个缓存处理线程和一池子网络分发线程。
当添加Request到RequestQueue的时候,请求先被缓存线程处理和鉴别:如果请求在缓存中有,则将缓存的response响应在缓存线程中进行解析并将解析后的响应分发给主线程。
如果缓存中没有这个Request请求,则将这个Request放到网络队列中。第一个可用的网络线程将Request请求从队列中取出来,执行HTTP传输,并在工作线程中解析响应,将响应写进缓存,并将解析好的响应内容传给主线程进行分发。
Volley将像IO、解析等耗时操作都放到了工作线程(子线程)来执行。你可以在任何线程去添加请求,Volley会将响应直接在主线程去进行分发。
调用Request.cancel()方法。在onStop()方法中调用,因为一旦请求被取消volley会确保你的响应不会被执行,在onStop()方法中执行的话不需要判断getActivity()==null来判断掠过处理结果其他类似onSaveInstanceState()等保护性方法里面也不需要检测。
requestQueue.cancelAll(this)
为每个请求的对象都绑定一个tag对象,使用tag来提供取消的范围。所有请求都绑定到执行的Activity上(以Activity的this作为Request的tag),然后你可以在 onStop() 方法执行 requestQueue.cancelAll(this) 来取消这些请求。同样的,你可以为ViewPager中的所有请求图片的Request对象分别打上对应Tab的tag。并在滑动时取消这些请求,用来确保新生成的tab不会被前面tab的请求任务阻塞。
我们是通过“Volley.newRequestQueue”方法来获取RequestQueue的实例的,Volley先构建了BasicNetwork和DiskBasedCache,然后将这两个对象作为参数传递给了RequestQueue,构建出了RequestQueue对象。紧接着,调用了RequestQueue.start()方法,开启了消息队列。
2.3之后HTTPURLConnection更适合安卓:因为它的API更简单,包更小,支持网络缓存,提高了速度节省电量。
更易于定制:底层可以定制自己想要的方法实现网络请求。
在“RequestQueue.start()”中,我们先在start之前进行了stop操作,然后先后构建了缓存线程CacheDispatcher和网络线程NetworkDispatcher,并将它们开启了。
说CacheDispatcher和NetworkDispatcher是线程,是因为它们实际上都是Thread的子类,因此,调用CacheDispatcher或者NetworkDispatcher对象的start()方法,最终关键逻辑一定是走的是run()方法。
1. CacheDispatcher被开启的时候,内部实际上是维护这一个while(true)死循环,不停的从队列中取Request;
2. 取到Request之后,判断Request的状态是否是被取消的状态,若被取消,则不做任何处理;
3. 若Request没有被取消,则看是否有这个Request对应的缓存数据,若没有缓存数据,则将Request添加到网络队列中去;
4. 有缓存数据,则判断缓存数据是否已经过期,若数据过期,则添加Request到网络队列;
5. 若缓存数据没有过期,则将缓存的原始二进制数据解析成对应的Response数据,比如如果请求的是StringRequest就将二进制数据解析成String;
6. 将解析好的Response响应分发到主线程,将解析好的Response分发到主线程调用的是“mDelivery.postResponse(request, response);”,而这个mResponsePoster实际上是一个线程池,它重写了自己的execute方法,在execute方法执行时,将对应的Runnable对象借助Handler分发到了主线程去执行,因此,我们的Response响应最终会在主线程被调用方接收并进行处理。
1. NetworkDispatcher被开启的时候,内部实际上是维护这一个while(true)死循环,不停的从队列中取Request;
2. 取到Request之后,判断Request的状态是否是被取消的状态,若被取消,则不做任何处理;
3. 若Request没有被取消,则根据Request去执行网络请求,获取响应Response;
4. 将响应的原始二进制数据解析成对应的Response数据,比如如果请求的是StringRequest就将二进制数据解析成String;
5. 缓存响应的数据Response;
6. 将响应的信息分发到主线程
执行网络网络请求,获取Request对应的响应Response,调用的是“mNetwork.performRequest(request)”方法,实际上底层执行的是HurlStack或者HttpClientStack中的performRequest方法。若是执行HurlStack的performRequest方法,则底层其实是调用的HttpURLConnection;若是执行HttpClientStack的performRequest方法,则底层其实是调用的HttpConnection。
分发Response到主线程的逻辑与CacheDispatcher中的分发逻辑完全一致。
创建一个RequestQueue是非常消耗资源的,在一个Application中只需维护一个RequestQueue的实例就可以了。
在写应用的时候,我们可以采用单例模式来管理RequestQueue的实例,节省资源的开销。
标准的Volley请求有:
StringRequest、ImageRequest、JsonObjectRequest (JsonArrayRequest)
区别就是new的对象和传的参数不一样
(1)StringRequest
StringRequest request = new StringRequest(
要访问的URL,
new Response.Listener
new Response.ErrorListener() {}); //请求结果错误返回的lisetner
(2)ImageRequest
ImageRequest request = new ImageRequest(
要访问的URL,
new Response.Listener
0, //压缩比,不想压缩就传0
0, //压缩比,不想压缩就传0
null, //伸缩,null不做任何处理
Bitmap.Config.RGB_565, //想让图片显示的质量,RGB_565、ARGB_8888、ARGB_4444
new Response.ErrorListener() {}); //请求结果错误返回的listener
(3)JsonObjectRequest
JsonObjectRequest request = new JsonObjectRequest(
要请求的URL,
params, //要向服务器传入的参数
new Response.Listener
new Response.ErrorListener() {}); //请求结果错误返回的listener
(4)ImageLoader:不使用内存缓存,则给一个默认的ImageCache,不重写里面的方法
mImageLoader = new ImageLoader(
mRequestQueue, //请求队列
new ImageLoader.ImageCache() {重写getBitmap和putBitmap}); //imageloader的缓存在普通缓存前执行
使用ImageLoader加载图片
mImageLoader.get(
URL, //要请求图片的地址
ImageLoader.getImageListener(
mIv, //显示到哪
R.mipmap.ic_launcher, //默认显示图片的资源id
R.mipmap.ic_launcher) //请求失败显示的图片
);
(5)NetworkImageView:加载网络图片
在布局文件中:
android:id="@+id/niv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> 在代码中(前两步跟ImageLoader一样,最后一步如下): mNiv.setImageUrl(URL, mImageLoader); 自定义Request需要实现两步: 1. 继承Request 2. 实现抽象方法 parseNetworkResponse() 和 deliverResponse() 自定义request