volley是什么?
volley是2013年Google I/O大会上推出了一个新的网络通信框架,封装了http网络请求的通信细节,能够简单的进行http请求,简单地处理网络图片。
a. 生成Request对象
b. 创建RequestQueue
c. 将Request加入到RequestQueue中,网络请求完成后,会有调用Request对象的回调函数。
mQueue = Volley.newRequestQueue(this);
stringRequest= new StringRequest("http://www.baidu.com", new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Debug.d(this, response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Debug.d(this, error.toString());
}
});
mQueue.add(stringRequest);
现有的Request子类有
StringRequest
JsonObjectRequest
JsonArrayRequest
ImageRequest
支持定制
如何跟踪volley的日志输出?
VolleyLog这个类来控制调试信息的输出,
默认是使用"Volley"这个tag,实际当中会定制专属自己app的tag。
默认情况下,logcat捕捉不到调试信息,需要在adb中开启log打印。
E:\ws\git\volley>adb devices
List of devices attached
A0Y9G9RTKZ device
adb -s A0Y9G9RTKZ shell setprop log.tag.Volley VERBOSE
这个是我们写log时可以借鉴的机制。
如何修改Request的优先级?
基类Request有该方法,默认都是NORMAL级别的,继承类可以通过改写getPriority来修改优先级。
/**
* Priority values. Requests will be processed from higher priorities to
* lower priorities, in FIFO order.
*/
public enum Priority {
LOW,
NORMAL,
HIGH,
IMMEDIATE
}
/**
* Returns the {@link Priority} of this request; {@link Priority#NORMAL} by default.
*/
public Priority getPriority() {
return Priority.NORMAL;
}
如何取消Request?
加入队列时,
stringRequest.setTag(TAG);
mRequestQueue.add(stringRequest);
取消时
mRequestQueue.cancelAll(TAG);
比如用在ViewPager当中
特定的请求不加入缓存中
Request方法
/**
* Returns true if responses to this request should be cached.
*/
public final boolean shouldCache() {
return mShouldCache;
}
删除特定url对应的缓存
AppController.getInstance().getRequestQueue().getCache().remove(url);
删除所有缓存
AppController.getInstance().getRequestQueue().getCache().clear();
Volley默认的缓存是个什么样的概念?
Volley默认使用的是磁盘缓存
Volley.java
/**
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
* You may set a maximum size of the disk cache in bytes.
*
* @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.
* @param maxDiskCacheBytes the maximum size of the disk cache, in bytes. Use -1 for default size.
* @return A started {@link RequestQueue} instance.
*/
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
...
// 默认采用的是磁盘缓存---DiskBaseCache
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
// No maximum size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else
{
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();
return queue;
}
NetworkDispatcher.java
@Override
public void run() {
...
// Parse the response here on the worker thread.
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// 写入缓存
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
...
}
使用ImageRequest来请求图片有什么好处?
ImageRequest是Request的子类,使用上来和Request一样方便。
. 返回Bitmap,
. 轻松改变图片尺寸
. 耗时的图片处理放在工作线程中
加载单个网络图片,使用ImageRequest,但是在ListView或者GridView这种使用很多图片的情形下,一般使用ImageLoader + NetworkImageView。
android sdk提供的示例代码
ImageLoader mImageLoader;
NetworkImageView mNetworkImageView;
private static final String IMAGE_URL =
"http://developer.android.com/images/training/system-ui.png";
...
// Get the NetworkImageView that will display the image.
mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);
// Get the ImageLoader through your singleton class.
mImageLoader = MySingleton.getInstance(this).getImageLoader();
// Set the URL of the image that should be loaded into this view, and
// specify the ImageLoader that will be used to make the request.
mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
为什么要使用ImageLoader?
Volley默认使用的缓存是磁盘缓存,在ListView显示大量图片的情形下,使用磁盘缓存速度并不是那么令人满意,有个特定的现象叫flicker,ImageLoader引入了内存缓存,在使用volley提供的磁盘缓存之前,先在内存缓存中搜索。
为什么要使用NetworkImageView?
在ListView中显示大量图片时,ImageView是复用的,这可能出现图形错乱的现象。
NetworkImageView是ImageView的子类,
会取消上一个无效的请求。
public void setImageUrl(String url, ImageLoader imageLoader) {
mUrl = url;
mImageLoader = imageLoader;
// The URL has potentially changed. See if we need to load it.
loadImageIfNecessary(false);
}
/**
* Loads the image for the view if it isn't already loaded.
* @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.
*/
void loadImageIfNecessary(final boolean isInLayoutPass) {
// if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content
// view, hold off on loading the image.
...
// if the URL to be loaded in this view is empty, cancel any old requests and clear the
// currently loaded image.
...
// if there was an old request in this view, check if it needs to be canceled.
...
// Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.
...
// The pre-existing content of this view didn't match the current URL. Load the new image
// from the network.
...
// update the ImageContainer to be the new bitmap container.
...
}
volley能否加载本地图片?
stack overflow 上的问答
Let Volley's NetworkImageView show local image files
用ImageLoader是可以实现的,和普通的网络图片请求没差别,除了url是本地类型的。
使用内存缓存,根据url判断,如果是本地图片,直接加载图片。但验证了下,这一过程是在UI线程中进行的,所以不推荐使用Volley来加载本地图片
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20);
@Override
public Bitmap getBitmap(String url) {
if (url.contains("file://")) {
// url地址类似于 #W0#H0#S3file:///data/data/com.example.jacksonke.volleydemo/files/1.png
String tmppath = url.substring(url.indexOf("file://") + 7);
Bitmap bitmap = BitmapFactory.decodeFile(url.substring(url.indexOf("file://") + 7));
// TODO 处理图片尺寸
if (bitmap != null){
putBitmap(url, bitmap);
}
// 如果本地图片不存在呢?返回是null,会走volley网络请求的流程,这样是否有其他问题
// 加载图片失败,会使用默认的失败图片
return bitmap;
}
else {
return cache.get(url);
}
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});