Android图片 * 缓存开发
作者:WhatYouSeeMe 发布时间:2023-12-03 22:42:43
标签:Android,图片缓存
因为目前工程无法使用第三方,只能搞一个 * 缓存了 * 缓存分为内存缓存,本地缓存,网络缓存;缓存的步骤依次是网络,内存,本地,然后取的顺序为内存,本地,网络。在加载图片时引用时尽量采用弱引用避免出现图片过多产生OOM.。
1、内存缓存,android为我们提供LruCache=其中维护着一个LinkedHashMap。LruCache可以用来存储各种类型的数据,我们设置它的大小,一般是系统最大存储空间的1/8.
public class MemoryCacheUtil {
private LruCache<String, Bitmap> lruCache;
public MemoryCacheUtil(){
int maxSize = (int) (Runtime.getRuntime().maxMemory()/8);
// 一般获取当前应用的最大内存的1/8作为LruCache的容量
lruCache = new LruCache<String, Bitmap>(maxSize){
// 设置当前添加的图片的大小
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
}
};
}
// 从内存缓存取图片
public Bitmap getBitmap(String url){
return lruCache.get(url);
}
// 在内存缓存存图片
public void putBitmap(String url,Bitmap bitmap){
lruCache.put(url, bitmap);
}
}
2、本地缓存根据url,获取本地文件,把url进行md5加密,作为文件名,保证文件的正确性.
MD5加密工具类
public class MD5Encoder {
public static String encode(String string) throws Exception {
byte[] hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) {
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
}
本地缓存
public class LocalCacheUtil {
private String CACHE_URl;
private MemoryCacheUtil memoryCacheUtil;
public LocalCacheUtil(MemoryCacheUtil memoryCacheUtil){
// 初始化本地存储的路径
CACHE_URl = Environment.getExternalStorageDirectory().getAbsoluteFile()+ "/test";
this.memoryCacheUtil = memoryCacheUtil;
}
// 从本地sdcard取图片
public Bitmap getBitmap(String url){
// 根据url,获取本地文件,把url进行md5加密,作为文件名
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_URl, fileName);
if(file.exists()){// 判断当前文件是否存在
// 把当前文件转换成Bitmap对象
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
// 需往内存中存一份
memoryCacheUtil.putBitmap(url, bitmap);
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 往本地存图片的方法
public void saveBitmap(String url,Bitmap bitmap){
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_URl, fileName);
// 判断是否需要创建父目录
File parentFile = file.getParentFile();
if(!parentFile.exists()){
parentFile.mkdirs();
}
// 把Bitmap对象保存到文件中 质量越高压缩速度越慢
OutputStream stream = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 100, stream);//第一个参数可以设置图片格式,第二个图片压缩质量,第三个为图片输出流
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、网络缓存使用异步加载AsyncTask,使用其有二种原因:
1.doInBackground运行在子线程,做网络请求耗时操作,避免主线程堵塞;
2.onPreExecute和onPostExecute便于更新UI提高用户体验。
public class NetCacheUtil {
private MemoryCacheUtil memoryCacheUtil;
private LocalCacheUtil localCacheUtil;
private ListView lv_image_list;
public NetCacheUtil(MemoryCacheUtil memoryCacheUtil,LocalCacheUtil localCacheUtil){
this.memoryCacheUtil = memoryCacheUtil;
this.localCacheUtil = localCacheUtil;
}
public void display(ImageView imageView ,String url, ListView lv_image_list){
this.lv_image_list = lv_image_list;
new MyAsyncTask(imageView).execute(new Object[]{url,imageView});
}
class MyAsyncTask extends AsyncTask<Object, Void, Bitmap>{
private ImageView imageView;
private int position;
public MyAsyncTask(ImageView imageView2) {
position = (Integer) imageView2.getTag();
}
// 运行在主线程,做准备操作,在doInBackground之前,可以放置加载条提高用户体验
@Override
protected void onPreExecute() {
super.onPreExecute();
}
// 运行在子线程,做耗时操作
@Override
protected Bitmap doInBackground(Object... params) {
// 获取url,下载图片
String url = (String) params[0];
// 获取ImageView
imageView = (ImageView) params[1];
try {
// 下载图片
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.connect();// 连接网络
// 获取响应码
int resCode = conn.getResponseCode();
if(resCode==200){// 访问成功
// 把服务器返回的输入流转换成Bitmap对象
Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream());
// 保存到本地和内存
memoryCacheUtil.putBitmap(url, bitmap);
localCacheUtil.saveBitmap(url, bitmap);
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 运行在主线程,更新界面,在doInBackground之后
@Override
protected void onPostExecute(Bitmap result) {
// 判断线程开始时,那个位置是否还在Listview中
ImageView view = (ImageView) lv_image_list.findViewWithTag(position);
if(view!=null){
view.setImageBitmap(result);
}
super.onPostExecute(result);
}
}
}
4、封装 * 缓存形成ImageUtil,因内存缓存中取速度较快,所以先从内存缓存中取,取不到->本地缓存中取,取不到->网络缓存中取。
public class ImageUtils {
private MemoryCacheUtil memoryCacheUtil;
private LocalCacheUtil localCacheUtil;
private NetCacheUtil netCacheUtil;
public ImageUtils(){
memoryCacheUtil = new MemoryCacheUtil();
localCacheUtil = new LocalCacheUtil(memoryCacheUtil);
netCacheUtil = new NetCacheUtil(memoryCacheUtil,localCacheUtil);
}
public void display(ImageView imageView, String url, ListView lv_photo_list) {
Bitmap bitmap = null;
/**
* 因内存缓存中取速度较快
* 内存缓存中取,取不到->本地缓存中取,取不到->网络缓存中取
*/
bitmap = memoryCacheUtil.getBitmap(url);//从内存缓存取图片
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
return;
}
bitmap = localCacheUtil.getBitmap(url);//从本地缓存取图片
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
return;
}
// 开启线程访问网络,下载图片,并且展示
netCacheUtil.display(imageView, url,lv_photo_list);
}
}
来源:http://blog.csdn.net/wangjiangjun0815/article/details/77717820
0
投稿
猜你喜欢
- 通常情况下,Android实现自定义控件无非三种方式。Ⅰ、继承现有控件,对其控件的功能进行拓展。Ⅱ、将现有控件进行组合,实现功能更加强大控件
- 本文实例讲述了Android获取SD卡及手机ROM容量的方法。分享给大家供大家参考,具体如下:这里通过一个简单的小例子,来获取SD卡的容量和
- Ctrl+1 快速修复Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复制当
- 1.launch启动协程fun main() = runBlocking { launch { &
- Timer 详解Timer 和 TimerTask 用于在后台线程中调度任务的 java.
- 前言最近在知乎上面看到一篇关于程序员面试的问题,面试官问我们一般有几种注入的方法,这几种注入的方法分别在什么时候运用比合理,当时我看到这个时
- 为了防止,页面向数据库暴力注册入力,用户登录暴力破解,所以加入验证码,验证码无法被软件获取上边的内容(加入算数计算,更加安全),所以在现在技
- 前言最近测试反馈一个问题,某个查询全量信息的接口,有时候返回全量数据,符合预期,但是偶尔又只返回1条数据,简直就是“见鬼
- SpringDataJpa创建中间表//fetch=FetchType.EAGER 关闭懒加载 相当于hibernate中的lazy=fal
- 向shell提供命令非常简单,需要学习的注解很少。该命令的实现风格与使用依赖注入的应用程序的开发类相同,您可以利用Spring容器的所有特性
- 在我们的程序当中如果要实现类似《360软件管家》的功能,就要解决两个问题,首先是要判断该程序已有一个实例在运行,其次是要将已运行的应用程序实
- 本文实例讲述了C#查找对象在ArrayList中出现位置的方法。分享给大家供大家参考。具体分析如下:我们可以通过IndexOf方法来查找对象
- 概述企业内部一般都有一套单点登录系统(常用的实现有apereo cas),所有的内部系统的登录认证都对接它。本文介绍spring boot的
- Java注解的Excel导出依赖: <dependency> &
- 一、导入依赖普通项目<dependency> <groupId>ch.qos.logbac
- 一、int还记得 C 语言里的 int 吗,C里面的 int 有着无符号与有符号之分但是Java内就没有,且固定占4个字节大小,也就是32比
- 这篇文章主要介绍了spring boot如何指定启动端口,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- resultType 与 parameterType 的基本使用的区别1、使用 resultType:主要针对于从数据库中提取相应的数据出来
- break和continue的说明break 循环结构,一旦执行,就结束(或跳出)当前循环结构,此关键字的后面,不能
- 本文实例讲述了java在网页上面抓取邮件地址的方法。分享给大家供大家参考。具体实现方法如下:import java.io.BufferedR