详细解读Volley(三)—— ImageLoader & NetworkImageView
ImageLoader是一个加载网络图片的封装类,其内部还是由ImageRequest来实现的。但因为源码中没有提供磁盘缓存的设置,所以咱们还需要去源码中进行修改,让我们可以更加自如的设定是否进行磁盘缓存。
一、添加对磁盘缓存的控制
我们默默的打开源码,添加如下代码:
private boolean mShouldCache = true;
/**
* Set whether or not responses to this request should be cached(Disk Cache).
*
* @return This Request object to allow for chaining.
*/
public void setShouldCache(boolean shouldCache) {
mShouldCache = shouldCache;
} /**
* Returns true if responses to this request should be cached.
*/
public final boolean shouldCache() {
return mShouldCache;
}
定位到get方法
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight)
找到初始化Request<Bitmap>的地方。
public ImageContainer get(String requestUrl, ImageListener imageListener,
int maxWidth, int maxHeight) {
// only fulfill requests that were initiated from the main thread.
throwIfNotOnMainThread(); final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight); // Try to look up the request in the cache of remote images.
Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
if (cachedBitmap != null) {
// Return the cached bitmap.
ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
imageListener.onResponse(container, true);
return container;
} // The bitmap did not exist in the cache, fetch it!
ImageContainer imageContainer =
new ImageContainer(null, requestUrl, cacheKey, imageListener); // Update the caller to let them know that they should use the default bitmap.
imageListener.onResponse(imageContainer, true); // Check to see if a request is already in-flight.
BatchedImageRequest request = mInFlightRequests.get(cacheKey);
if (request != null) {
// If it is, add this request to the list of listeners.
request.addContainer(imageContainer);
return imageContainer;
} // The request is not already in flight. Send the new request to the network and
// track it.
Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, cacheKey);
mRequestQueue.add(newRequest);
mInFlightRequests.put(cacheKey,
new BatchedImageRequest(newRequest, imageContainer));
return imageContainer;
}
把红色代码中间添加:newRequest.setShouldCache(mShouldCache);最终效果如下:
// The request is not already in flight. Send the new request to the network and
// track it.
Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, cacheKey);
newRequest.setShouldCache(mShouldCache);
mRequestQueue.add(newRequest);
二、ImageLoader
/**
* Constructs a new ImageLoader.
* @param queue The RequestQueue to use for making image requests.
* @param imageCache The cache to use as an L1 cache.
*/
public ImageLoader(RequestQueue queue, ImageCache imageCache) {
mRequestQueue = queue;
mCache = imageCache;
}
初始化要传入两个参数:①RequestQueue对象;②ImageCache对象(不能传null!!!!)
RequestQueue这个我就不多说了,之前的文章已经讲解过了,下面来说说ImageCache这个对象。
2.1 建立ImageCache对象来实现内存缓存
ImageCache是一个图片的内存缓存对象,源码中叫做L1缓存,其实缓存分为L1、L2两种,L1就是所谓的内存缓存,将展示过的图片放入内存中进行缓存,L2就是磁盘缓存,如果这个图片下载完成,它可以被存放到磁盘中,在没有网络的时候就可以调出来使用了。
为了简单我先空实现ImageCache接口,产生一个MyImageCache对象
class MyImageCache implements ImageCache {
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
}
这个接口提供的方法简单明了,今后我们可以用自己的内存缓存来完善这个类,当前getBitmap返回的是null,说明这个内存缓存没啥用处,和没缓存一样。
2.2 实现加载网络图片
ImageLoader imageLoader = new ImageLoader(mQueue, new MyImageCache());
ImageListener listener = ImageLoader.getImageListener(iv, R.drawable.default_photo, R.drawable.error_photo);
imageLoader.setShouldCache(true);
imageLoader.get("http://img5.duitang.com/uploads/item/201409/14/20140914162144_MBEmX.jpeg", listener);
代码的思路是产生ImageLoader后,再初始化一个监听器,监听器中传入imageview对象,还有默认的图片,出错时展示的图片,这个很好理解。最后在imageLoader的get方法中传入URL,还有监听器对象即可。
值得注意的是,get方法还有一种变体:
imageLoader.get("http://img5.duitang.com/uploads/item/201409/14/20140914162144_MBEmX.jpeg", listener, 0 ,0);
这里最后传入的数值是得到图片的最大宽、高,其意义和ImageRequest中的宽、高完全一致,可以参考之前的文章。其实,如果你去源码中找找的话,你会发现这两个参数最终都是传给ImageRequest的,所以在此就不做过多讲解了。
2.3 设置缓存
因为我们一上来就修改了源码,所以当我们在执行get()方法前可以通过setShouldCache(false)来取消磁盘缓存,如果你不进行设置的话默认是执行磁盘缓存的。那么如何配置L1缓存呢?刚刚我们的MyImageCache仅仅是一个空实现,现在就开始来完善它。
我的想法是通过LruCache进行图片缓存,分配的缓存空间是5m。如果对LruCache不是很了解,可以看看我之前的文章:详细解读LruCache类
class MyImageCache implements ImageCache {
private LruCache<String, Bitmap> mCache;
public MyImageCache() {
int maxSize = 5 * 1024 * 1024;
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
@Override
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
}
每次执行get方法时,Volley会到MyImageCache中调用getBitmap(),看看有没有内存缓存,如果你返回了null,那么Volley就会从网络上下载,如果不为null,Volley会直接把取得的bitmap展示到imageview中。当图片展示到屏幕上后(无论是这个图片是从内存中读的,还是从磁盘中读的,或者是从网络上下载的),Volley都会自动调用putBitmap,把图片放入内存中缓存起来。
说明:缓存的size是:bitmap.getRowBytes() * bitmap.getHeight(),这里getRowBytes()是返回图片每行的字节数,图片的size应该乘以高度。
注意:imageLoader.setShouldCache(false);仅仅是设置了不实用磁盘缓存,和内存缓存没有任何关系。如果你想要不实用内存缓存,请在自定义的ImageCache中进行处理。
2.4 其他方法
public final boolean shouldCache()
查看是否已经做了磁盘缓存。
void setShouldCache(boolean shouldCache)
设置是否运行磁盘缓存,此方法需要在get方法前使用
public boolean isCached(String requestUrl, int maxWidth, int maxHeight)
判断对象是否已经被缓存,传入url,还有图片的最大宽高
public void setBatchedResponseDelay(int newBatchedResponseDelayMs)
Sets the amount of time to wait after the first response arrives before delivering all responses. Batching can be disabled entirely by passing in 0.
设置第一次响应到达后到分发所有响应之前的整体时间,单位ms,如果你设置的时间是0,那么Batching将不可用。
三、NetworkImageView
NetworkImageView继承自ImageView,你可以认为它是一个可以实现加载网络图片的imageview,十分简单好用。这个控件在被从父控件分离的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题。
3.1 XML
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/network_image_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal" />
3.2 JAVA
NetworkImageView networkImageView = (NetworkImageView) findViewById(R.id.network_image_view);
networkImageView.setDefaultImageResId(R.drawable.default_photo);
networkImageView.setErrorImageResId(R.drawable.error_photo);
networkImageView.setImageUrl("http://img5.duitang.com/uploads/item/201409/14/20140914162144_MBEmX.jpeg", imageLoader);
3.3 设置图片的宽高
NetworkImageView没有提供任何设置图片宽高的方法,这是由于它是一个控件,在加载图片的时候它会自动获取自身的宽高,然后对比网络图片的宽度,再决定是否需要对图片进行压缩。也就是说,压缩过程是在内部完全自动化的,并不需要我们关心。NetworkImageView最终会始终呈现给我们一张大小比控件尺寸略大的网络图片,因为它会根据控件宽高来等比缩放原始图片,这点需要注意,如果你想要了解详细原理,请看我之前的ImageRequest介绍。
如果你不想对图片进行压缩的话,只需要在布局文件中把NetworkImageView的layout_width和layout_height都设置成wrap_content就可以了,这样它就会将该图片的原始大小展示出来,不会进行任何压缩。
参考自:
http://blog.csdn.net/guolin_blog/article/details/17482165
详细解读Volley(三)—— ImageLoader & NetworkImageView的更多相关文章
- 详细解读Volley(二)—— ImageRequest & Request简介
上篇文章我们讲到了如何用volley进行简单的网络请求,我们可以很容易的接受到string.JsonObjec类型的返回结果,之前的例子仅仅是一次请求,这里需要说明volley本身就是适合高并发的,所 ...
- 详细解读Volley(五)—— 通过源码来分析业务流程
一.初始化请求队列并运行 我们用Volley时,最先开始的就是初始化请求队列,一种常见的写法如下: public class MyApplication extends Application { p ...
- 详细解读Volley(四)—— 自定义Request
Volley中提供了几个Request,如果我们有特殊的需求,完全可以自定义Request的,自定义Request自然要继承Request,那么本篇就教大家来一步一步地定义一个自己的Request类. ...
- 详细解读Volley(一)—— 基本Request对象 & RequestQueue
Volley它非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕.所以不建议用它去进行下载文件.加载大图的操作.有人可能会问,如 ...
- Volley(四)—— ImageLoader & NetworkImageView
Volley(四)—— ImageLoader & NetworkImageView ImageLoader是一个加载网络图片的封装类,其内部还是由ImageRequest来实现的.但因为源码 ...
- volley三种基本请求图片的方式与Lru的基本使用:正常的加载+含有Lru缓存的加载+Volley控件networkImageview的使用
首先做出全局的请求队列 package com.qg.lizhanqi.myvolleydemo; import android.app.Application; import com.android ...
- 相机IMU融合四部曲(三):MSF详细解读与使用
相机IMU融合四部曲(三):MSF详细解读与使用 极品巧克力 前言 通过前两篇文章,<D-LG-EKF详细解读>和<误差状态四元数详细解读>,已经把相机和IMU融合的理论全部都 ...
- volley get post json imagerequest imageloader networkimageview 加载网络本地图片
官方网站 https://www.androidhive.info/2014/05/android-working-with-volley-library-1/ private void initL ...
- Android-Volley网络通信框架(ImageRequest,ImageLoader,NetWorkImageView)
1.回想 上篇已经学习了,RequestQueue , StringRequest ,JsonObjectRequest 的使用 2.重点 (1)Volley请求图片的三种方式 (2)ImageRe ...
随机推荐
- WinForm1
一.窗体的各种属性 二.控件 1.公共控件 2.容器控件 3.菜单控件
- SQL Server 2
一.创建数据表 1.连接服务器: 2.右击“表”节点,选择“新建表”,即: 3.在弹出的“表设计器”中,输入表的列名.选择的数据类型及是否允许为空,即: 二.导入数据表 1.右击表名,弹出菜单,选择“ ...
- flume修改配置文件
flume修改配置文件后,flume进程会自动将配置文件更新至服务中,同时会初始化日志,重新对于metrics进行记录的. 所以拿api做监控的同学要注意这点啦
- div左边固定宽度,右边自适应宽度
样式: <style type="text/css"> html,body { height: 100%; padding: 0; margin: 0; } .oute ...
- shiro xml标准配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- Ubuntu服务器的anaconda环境修复办法(自动进入base环境怎么办?)
某天在服务器上更新了conda的版本,不知怎么回事我的python3.6就变成python2.7了,而且一进入服务器就会自动进入base环境(我的conda只装了base环境) 仔细研究了半天,才发现 ...
- 关于dubbo和zookeeper 注册中心
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载.如果不想使用Sprin ...
- BZOJ2190 [SDOI2008]仪仗队 [欧拉函数]
题目描述 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图 ...
- maven -- 问题解决(四)警告Classpath entry org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER will not be exported or published
警告:Classpath entry org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER will not be exported or published. Run ...
- 轻量级IOC框架:Ninject (上)
前言 前段时间看Mvc最佳实践时,认识了一个轻量级的IOC框架:Ninject.通过google搜索发现它是一个开源项目,最新源代码地址是:http://github.com/enkari/ninje ...