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

Android结合volley的netWorkImageview实现图片文件缓存

2015-08-13 11:20 477 查看
在写Android应用程序时经常会用到图片缓存,对于网络请求使用Android平台上的网络通信库Volley,能使网络通信更快,更简单,更健壮,而且Volley特别适合数据量不大但是通信频繁的场景,所以可以使用volley来请求网络图片。接下来就将本人在一个项目中的图片缓存模块拿出来跟大家分享,欢迎批评指正。

/**
* @author
* @date 2015/4/14
* 利用文件缓存图片
*/

public class ImageFileCacheUtils {
private static final String CHCHEDIR = "ImageChace";//缓存目录
private static final String WHOLESALE_CONV = ".cache";//缓存文件后缀名
private static final int MB = 1024 * 1024;
private static final int CACHE_SIZE = 80;//缓存最大容量(超过就会利用lru算法删除最近最少使用的缓存文件)
private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 100;//缓存所需SD卡所剩的最小容量

private static ImageFileCacheUtils instance = null;
//单例模式
public static ImageFileCacheUtils getInstance(){
if (instance == null) {
synchronized (ImageFileCacheUtils.class) {
if (instance == null) {
instance = new ImageFileCacheUtils();
}
}
}
return instance;
}

public ImageFileCacheUtils(){
removeCache(getDirectory());
}

/**
* 从文件缓存中获取图片
* @param url
* @return
*/
public Bitmap getImage(final String url){
final String path = getDirectory() + "/" +convertUrlToFileName(url);
File file = new File(path);
if(file.exists()){
Bitmap bitmap = BitmapFactory.decodeFile(path);
if(bitmap == null){
file.delete();
return null;
}else {
updateFileTime(path);//更新文件最新访问时间
return bitmap;
}
}else {
return null;
}
}

/**
* 获得缓存目录
* @return
*/
private String getDirectory() {
String dir = getSDPath() + "/" + CHCHEDIR;
return dir;
}

private String getSDPath(){
File sdDir = null;
boolean adCardExit = Environment.getExternalStorageState()
.endsWith(Environment.MEDIA_MOUNTED);//判断SD卡是否挂载
if (adCardExit) {
sdDir = Environment.getExternalStorageDirectory();//获取根目录
}
if (sdDir != null) {
return sdDir.toString();
}else {
return "";
}
}

/**
* 修改文件的最后修改时间
* @param path
*/
private void updateFileTime(String path) {
File file = new File(path);
long newModeifyTime = System.currentTimeMillis();
file.setLastModified(newModeifyTime);
}

public void saveBitmap(Bitmap bitmap,String url){
if (bitmap == null) {
return ;
}
//判断SD卡上的空间
if(FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()){
return;
}
String fileName = convertUrlToFileName(url);
String dir = getDirectory();
File dirFile = new File(dir);
if (!dirFile.exists()) {
dirFile.mkdirs();
}
File file = new File(dir + "/" +fileName);
try {
file.createNewFile();
OutputStream outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 计算sd卡上的剩余空间
* @return
*/
private int freeSpaceOnSd() {
StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getPath());
double sdFreeMB = ((double)statFs.getAvailableBlocks() * (double)statFs.getBlockSize()) / MB;
Log.i("test", "剩余空间为:"+sdFreeMB);
return (int)sdFreeMB;
}

/**
* 将url转成文件名
* @param url
* @return
*/
private String convertUrlToFileName(String url) {
String[] strs = url.split("/");
return strs[strs.length - 1] + WHOLESALE_CONV;
}

/**
* 计算存储目录下的文件大小
* 当文件总大小大于规定的大小或者sd卡剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定时
* ,那么删除40%最近没有被使用的文件
* @param dirPath
* @return
*/
private boolean removeCache(String dirPath){
File dirFile = new File(dirPath);
File[] files = dirFile.listFiles();
if (files == null || files.length <= 0) {
return true;
}
//如果sd卡没有挂载
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return false;
}
int dirSize = 0;
for (int i = 0; i < files.length; i++) {
if (files[i].getName().contains(WHOLESALE_CONV)) {
dirSize += files[i].length();
}
}
if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
int removeFactor = (int)((0.4 * files.length) + 1);
Arrays.sort(files, new FileLastModifySoft());
for (int i = 0; i < removeFactor; i++) {
if (files[i].getName().contains(WHOLESALE_CONV)) {
files[i].delete();
}
}
}
if (freeSpaceOnSd() <= CACHE_SIZE) {
return false;
}
return true;
}

//比较器类
private class FileLastModifySoft implements Comparator<File>{
@Override
public int compare(File arg0, File arg1) {
if (arg0.lastModified() > arg1.lastModified()) {
return 1;
}else if (arg0.lastModified() == arg1.lastModified()) {
return 0;
}else {
return -1;
}
}
}
}
利用volley的networkImageview加载图片时需要传入一个ImageLoader,在构造ImageLoader时需要一个实现ImageCache接口的类,所以先构造此类:

public class ImageFileCache implements ImageCache{

@Override
public Bitmap getBitmap(String url) {
return ImageFileCacheUtils.getInstance().getImage(url);
}

@Override
public void putBitmap(String url, Bitmap bitmap) {
ImageFileCacheUtils.getInstance().saveBitmap(bitmap, url);
}

}
接下来使用networkImageview加载网络图片:

在布局文件中使用volley的自定义组件:

<com.android.volley.toolbox.NetworkImageView
android:id="@+id/activity_icon"
android:layout_width="@dimen/activity_icon_size_w"
android:layout_height="@dimen/activity_icon_size_h"
android:layout_marginRight="4dp"
android:scaleType="centerInside"
android:src="@drawable/activity_example" />


<pre name="code" class="java" style="color: rgb(85, 85, 85); font-size: 14px; line-height: 26px; orphans: 2; widows: 2;">//初始化imageLoader
ImageLoader imageLoader = new ImageLoader(Volley.newRequestQueue(context), new ImageFileCache());
activity_icon.setDefaultImageResId(R.drawable.activity_example);
activity_icon.setErrorImageResId(R.drawable.activity_example);
<pre name="code" class="java" style="color: rgb(85, 85, 85); font-size: 14px; line-height: 26px; orphans: 2; widows: 2;">holder.activity_icon.setImageUrl(a.getLogo(), imageLoader);


此模块可以直接使用在自己的项目中,希望可以帮助大家。

解析:

在实现ImageCache接口时,实现的两个方法  getBitmap   和   putBitmap  的调用时机分别是:①使用networkImageView加载图片时,首先代用getBitmap  方法,如果此方法返回的值为null,此时说明没有缓存此图片,就进行网络加载。②在进行网络加载完成后会调用   putBitmap  方法将网络获取到的图片以文件的形式缓存到SD卡,从而实现缓存的目的。

版权声明:本文为博主原创文章,需要转载,请以链接形式注明出处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息