图片池 android,Android 图片缓存(文件+缓存+网络+线程池)

我们在项目中,不可避免地会遇到要去加载网络图片,这些天倒腾下写出了些小东西,用于图片缓存的一些个工具。自己尝试写了下(一步一步来):

1.正常的加载图片(直接指定图片id)

imageView.setImageResource(DEFAULT_PIC_ID);

2.访问网络图片

大体思路是:先显示一张默认图片,然后开启一个线程去判断缓存TAG是否有图片,有则拿来显示,无则判断文件缓存,无则再去网络下载图片,并保存到本地文件目录。

2.1 新建图片加载项实体

public class PhotoToLoad {

protected String url;

protected ImageView imageView;

protected PhotoToLoad(String url, ImageView imageView) {

this.url = url;

this.imageView = imageView;

}

}

2.2 新建图片加载线程

class PhotoLoader implements Runnable {

PhotoToLoad photoToLoad;

PhotoLoader(PhotoToLoad photoToLoad) {

this.photoToLoad = photoToLoad;

}

@Override

public void run() {

if (imageViewReused(photoToLoad))

return;

Bitmap bmp = getBitmap(photoToLoad.url);

memoryCache.put(photoToLoad.url, bmp);

if (imageViewReused(photoToLoad))

return;

BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);

// 更新的操作放在UI线程中

Activity a = (Activity) photoToLoad.imageView.getContext();

a.runOnUiThread(bd);

}

}

2.3 去网络获取Bitmap方法

private Bitmap getBitmap(String url) {

// TODO 不明白为嘛这么搞?根据URL去创建一个新的文件

File f = fileCache.getFile(url);

// 先从文件缓存中查找是否有

Bitmap b = decodeFile(f);

if (b != null)

return b;

// 最后从指定的url中下载图片

try {

Bitmap bitmap = null;

URL imageUrl = new URL(url);

HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();

conn.setConnectTimeout(30000);

conn.setReadTimeout(30000);

conn.setInstanceFollowRedirects(true);

InputStream is = conn.getInputStream();

OutputStream os = new FileOutputStream(f);

CopyStream(is, os);

os.close();

bitmap = decodeFile(f);

return bitmap;

} catch (Exception ex) {

ex.printStackTrace();

return null;

}

}

2.4 文件缓存类

public class FileCache {

/**

* 文件集目录

*/

private File cacheDir;

private Context mContext;

public FileCache(final Context context) {

mContext = context;

// 1.如果有SD卡则在SD卡中建一个LazyList的目录存放缓存的图片

// 2.没有SD卡就放在系统的缓存目录中

if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))

//cacheDir = new File(android.os.Environment.getExternalStorageDirectory(), "LazyList");

cacheDir = new File(android.os.Environment.getExternalStorageDirectory(), mContext.getPackageName() + File.separator + "images");

else

cacheDir = context.getCacheDir();

if (!cacheDir.exists())

cacheDir.mkdirs();

}

public File getFile(String url) {

// 将Url的hashCode作为缓存的文件名

String fileName = String.valueOf(url.hashCode()) + ".png";

File f = new File(cacheDir, fileName);

return f;

}

/**

* 清除该目录下所有的文件

* @author chenxinyi2 2015年4月29日 下午2:42:54

*/

public void clear() {

File[] files = cacheDir.listFiles();

if (files == null)

return;

for (File f : files) {

f.delete();

}

}

}

2..5 内存缓存

public class MemoryCache {

/**

* TAG

*/

private final String TAG = MemoryCache.class.getSimpleName();

/**

* 缓存只能使用的最大堆内存

* max memory in bytes

*/

private long limit = 1000000;

/**

* 1.放入缓存是个同步操作

* 2.LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列,即LRU

* 3.这样的好处就是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率

*/

private Map cache = Collections.synchronizedMap(new LinkedHashMap(10, 1.5f, true));

/**

* 缓存中图片所占用的字节数,初始0,通过此变量严格控制缓存所占用的堆内存

*/

private long size = 0;

protected MemoryCache() {

// 这里严格限制只能使用最大JVM内存的 1 / 4.

this.limit = Runtime.getRuntime().maxMemory() / 4;

}

protected void put(String id, Bitmap bitmap) {

if (cache.containsKey(id))

size -= getSizeInBytes(cache.get(id));

cache.put(id, bitmap);

size += getSizeInBytes(bitmap);

checkSize();

}

/**

* 严格控制堆内存,如果超过将首先替换最近最少使用的那个图片缓存

* @author chenxinyi2 2015年4月29日 下午3:11:32

*/

private void checkSize() {

Log.i(TAG, "cache size=" + size + ", length=" + cache.size());

// 如果堆内存超出限制

if (size > limit) {

// 遍历最近最少使用的元素

Iterator> iter = cache.entrySet().iterator();

while(iter.hasNext()) {

Entry entry = iter.next();

size -= getSizeInBytes(entry.getValue());

iter.remove();

if (size <= limit)

break;

}

}

}

/**

* 获取bitmap

* @author chenxinyi2 2015年4月28日 下午4:27:29

* @param id

* @return

*/

protected Bitmap getBitmap(String id) {

// TODO 这里考虑吃掉空指针异常

if (!cache.containsKey(id))

return null;

return cache.get(id);

}

/**

* 图片占用的内存

*

* @param bitmap

* @return

*/

protected long getSizeInBytes(Bitmap bitmap) {

if (bitmap == null)

return 0;

return bitmap.getRowBytes() * bitmap.getHeight();

}

}

2.6 相关方法和类

/**

* 用于在UI线程中更新界面

* @author chenxinyi2

* @version 1.0.0 2015年4月29日 下午3:46:30

* @see

* @since JDK 1.7.0_45

*/

class BitmapDisplayer implements Runnable{

Bitmap bitmap;

PhotoToLoad photoToLoad;

public BitmapDisplayer(Bitmap b, PhotoToLoad p) {

bitmap = b;

photoToLoad = p;

}

@Override

public void run() {

if (imageViewReused(photoToLoad))

return;

if (bitmap != null)

photoToLoad.imageView.setImageBitmap(bitmap);

else

photoToLoad.imageView.setImageResource(DEFAULT_PIC_ID);

}

}

/**

* 图片是否在缓存中有值

*

* @param photoToLoad

* @return 缓存中是否有值

*/

boolean imageViewReused(PhotoToLoad photoToLoad) {

String tag = imageViews.get(photoToLoad.imageView);

if (tag == null || !tag.equals(photoToLoad.url))

return false;

return true;

}

private void CopyStream(InputStream is, OutputStream os) {

final int buffer_size = 1024;

try {

byte[] bytes = new byte[buffer_size];

for (;;) {

int count = is.read(bytes, 0, buffer_size);

if (count == -1)

break;

os.write(bytes, 0, count);

}

} catch (Exception ex) {

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值