版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、最新Android批量图片加载经典系列采用二级缓存、异步加载网络图片(烟台杰瑞教育Android培训部原创)Android批量图片加载经典系列采用二级缓存、异步加载网络图片一、问题描述Android应用中经常涉及从网络中加载大量图片,为提升加载速度和效率,减少网络流量都会采用二级缓存和异步加载机制,所谓二级缓存就是通过先从内存中获取、再从文件中获取,最后才会访问网络。内存缓存一级本质上是Map集合以key-value对的方式存储图片的url和Bitmap信息,由于内存缓存会造成堆内存泄露, 管理相对复杂一些,可采用第三方组件,对于有经验的可自己编写组件,而文件缓存比拟简单通常自己封装一下即可。
2、下面就通过案例看如何实现网络图片加载的优化。二、案例介绍案例新闻的列表图片三、主要核心组件下面先看看实现一级缓存内存、二级缓存磁盘文件所编写的组件1、MemoryCache在内存中存储图片一级缓存, 采用了1个map来缓存图片代码如下:public class MemoryCache / 最大的缓存数 private static final int MAX_CACHE_CAPACITY = 30; /用Map软引用的Bitmap对象, 保证内存空间足够情况下不会被垃圾回收 private HashMapString, SoftReference mCacheMap = new LinkedH
3、ashMapString, SoftReference() private static final long serialVersionUID = 1L;/当缓存数量超过规定大小返回true会去除最早放入缓存的 protected boolean removeEldestEntry(Map.EntryString,SoftReference eldest) return size() MAX_CACHE_CAPACITY; ; /* * 从缓存里取出图片 * param id * return 如果缓存有,并且该图片没被释放,那么返回该图片,否那么返回null */ public Bitma
4、p get(String id) if(!mCacheMap.containsKey(id) return null; SoftReference ref = mCacheMap.get(id); return ref.get(); /* * 将图片参加缓存 * param id * param bitmap */ public void put(String id, Bitmap bitmap) mCacheMap.put(id, new SoftReference(bitmap); /* * 去除所有缓存 */ public void clear() try for(Map.EntrySt
5、ring,SoftReferenceentry :mCacheMap.entrySet() SoftReference sr = entry.getValue(); if(null != sr) Bitmap bmp = sr.get(); if(null != bmp) bmp.recycle(); mCacheMap.clear(); catch (Exception e) e.printStackTrace(); 2、FileCache在磁盘中缓存图片(二级缓存),代码如下 public class FileCache /缓存文件目录 private File mCacheDir; /*
6、 * 创立缓存文件目录,如果有SD卡,那么使用SD,如果没有那么使用系统自带缓存目录 * param context * param cacheDir 图片缓存的一级目录 */public FileCache(Context context, File cacheDir, String dir)if().equals、() mCacheDir = new File(cacheDir, dir); else mCacheDir = context.getCacheDir();/ 如何获取系统内置的缓存存储路径 if(!mCacheDir.exists() mCacheDir.mkdirs();
7、public File getFile(String url) File f=null; try /对url进行编辑,解决中文路径问题 String filename = URLEncoder.encode(url,utf-8); f = new File(mCacheDir, filename); catch (UnsupportedEncodingException e) e.printStackTrace(); return f; public void clear()/去除缓存文件 File files = mCacheDir.listFiles(); for(File f:files
8、)f.delete();3、编写异步加载组件AsyncImageLoaderandroid中采用单线程模型即应用运行在UI主线程中,且Android又是实时操作系统要求及时响应否那么出现ANR错误,因此对于耗时操作要求不能阻塞UI主线程,需要开启一个线程处理如本应用中的图片加载并将线程放入队列中,当运行完成后再通知UI主线程进行更改,同时移除任务这就是异步任务,在android中实现异步可通过本系列一中所用到的AsyncTask或者使用thread+handler机制,在这里是完全是通过代码编写实现的,这样我们可以更清晰的看到异步通信的实现的本质,代码如下public class AsyncI
9、mageLoader private MemoryCache mMemoryCache;/内存缓存 private FileCache mFileCache;/文件缓存 private ExecutorService mExecutorService;/线程池/记录已经加载图片的ImageView private Map mImageViews = Collections .synchronizedMap(new WeakHashMap();/保存正在加载图片的url private List mTaskQueue = new ArrayList(); /* * 默认采用一个大小为5的线程池
10、* param context * param memoryCache 所采用的高速缓存 * param fileCache 所采用的文件缓存 */ public AsyncImageLoader(Context context, MemoryCache memoryCache, FileCache fileCache) mMemoryCache = memoryCache; mFileCache = fileCache; mExecutorService = Executors.newFixedThreadPool(5);/建立一个容量为5的固定尺寸的线程池最大正在运行的线程数量 /* *
11、根据url加载相应的图片 * param url * return 先从一级缓存中取图片有那么直接返回,如果没有那么异步从文件二级缓存中取,如果没有再从网络端获取 */ public Bitmap loadBitmap(ImageView imageView, String url) /先将ImageView记录到Map中,表示该ui已经执行过图片加载了 mImageViews.put(imageView, url); Bitmap bitmap = mMemoryCache.get(url);/先从一级缓存中获取图片 if(bitmap = null) enquequeLoadPhoto(u
12、rl, imageView);/再从二级缓存和网络中获取 return bitmap; /* * 参加图片下载队列 * param url */ private void enquequeLoadPhoto(String url, ImageView imageView) /如果任务已经存在,那么不重新添加 if(isTaskExisted(url) return; LoadPhotoTask task = new LoadPhotoTask(url, imageView); synchronized (mTaskQueue) mTaskQueue.add(task);/将任务添加到队列中 m
13、ExecutorService.execute(task);/向线程池中提交任务,如果没有到达上限(5),那么运行否那么被阻塞 /* * 判断下载队列中是否已经存在该任务 * param url * return */ private boolean isTaskExisted(String url) if(url = null) return false; synchronized (mTaskQueue) int size = mTaskQueue.size(); for(int i=0; isize; i+) LoadPhotoTask task = mTaskQueue.get(i);
14、 if(task != null & task.getUrl().equals(url) return true; return false; /* * 从缓存文件或者网络端获取图片 * param url */ private Bitmap getBitmapByUrl(String url) File f = mFileCache.getFile(url);/获得缓存图片路径 Bitmap b = ImageUtil.decodeFile(f);/获得文件的Bitmap信息 if (b != null)/不为空表示获得了缓存的文件 return b; return ImageUtil.lo
15、adBitmapFromWeb(url, f);/同网络获得图片 /* * 判断该ImageView是否已经加载过图片了可用于判断是否需要进行加载图片 * param imageView * param url * return */ private boolean imageViewReused(ImageView imageView, String url) String tag = mImageViews.get(imageView); if (tag = null | !tag.equals(url) return true; return false; private void re
16、moveTask(LoadPhotoTask task) synchronized (mTaskQueue) mTaskQueue.remove(task); class LoadPhotoTask implements Runnable private String url; private ImageView imageView; LoadPhotoTask(String url, ImageView imageView) this.url = url; this.imageView = imageView; Override public void run() if (imageView
17、Reused(imageView, url) /判断ImageView是否已经被复用 removeTask(this);/如果已经被复用那么删除任务 return; Bitmap bmp = getBitmapByUrl(url);/从缓存文件或者网络端获取图片 mMemoryCache.put(url, bmp);/ 将图片放入到一级缓存中 if (!imageViewReused(imageView, url) /假设ImageView未加图片那么在ui线程中显示图片 BitmapDisplayer bd = new BitmapDisplayer(bmp, imageView, url)
18、; Activity a = (Activity) imageView.getContext(); a.runOnUiThread(bd);/在UI线程调用bd组件的run方法,实现为ImageView控件加载图片 removeTask(this);/从队列中移除任务 public String getUrl() return url; /* * *由UI线程中执行该组件的run方法 */ class BitmapDisplayer implements Runnable private Bitmap bitmap; private ImageView imageView; private S
19、tring url; public BitmapDisplayer(Bitmap b, ImageView imageView, String url) bitmap = b; this.imageView = imageView; this.url = url; public void run() if (imageViewReused(imageView, url) return; if (bitmap != null) imageView.setImageBitmap(bitmap); /* * 释放资源 */ public void destroy() mMemoryCache.cle
20、ar(); mMemoryCache = null; mImageViews.clear(); mImageViews = null; mTaskQueue.clear(); mTaskQueue = null; mExecutorService.shutdown(); mExecutorService = null; 编写完成之后,对于异步任务的执行只需调用AsyncImageLoader中的loadBitmap()方法即可非常方便,对于AsyncImageLoader组件的代码最好结合注释好好理解一下,这样对于Android中线程之间的异步通信就会有深刻的认识。4、工具类ImageUtil
21、public class ImageUtil /* * 从网络获取图片,并缓存在指定的文件中 * param url 图片url * param file 缓存文件 * return */ public static Bitmap loadBitmapFromWeb(String url, File file) HttpURLConnection conn = null; InputStream is = null; OutputStream os = null; try Bitmap bitmap = null; URL imageUrl = new URL(url); conn = (Ht
22、tpURLConnection) imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); is = conn.getInputStream(); os = new FileOutputStream(file); copyStream(is, os);/将图片缓存到磁盘中 bitmap = decodeFile(file); return bitmap; catch (Exception ex) ex.p
23、rintStackTrace(); return null; finally try if(os != null) os.close(); if(is != null) is.close(); if(conn != null) conn.disconnect(); catch (IOException e) public static Bitmap decodeFile(File f) try return BitmapFactory.decodeStream(new FileInputStream(f), null, null); catch (Exception e) return nul
24、l; private static void copyStream(InputStream is, OutputStream os) final int buffer_size = 1024; try byte bytes = new bytebuffer_size; for (;) int count = is.read(bytes, 0, buffer_size); if (count = -1) break; os.write(bytes, 0, count); catch (Exception ex) ex.printStackTrace(); 四、测试应用组件之间的时序图:1、编写M
25、ainActivitypublic class MainActivity extends Activity ListView list; ListViewAdapter adapter; Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(); list=(ListView)findViewById(); adapter=new ListViewAdapter(this, mStrings); list.setAdapter(ada
26、pter); public void onDestroy() list.setAdapter(null); super.onDestroy(); adapter.destroy(); private String mStrings=.;2、编写适配器public class ListViewAdapter extends BaseAdapter private Activity mActivity; private String data; private static LayoutInflater inflater=null; private AsyncImageLoader imageLo
27、ader;/异步组件 public ListViewAdapter(Activity mActivity, String d) this.mActivity=mActivity; data=d; inflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); MemoryCache mcache=new MemoryCache();/内存缓存 File sdCard = ();/获得SD卡 File cacheDir = new File(sdCard, jereh_cache );/缓
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《建设工程施工合同示范文本》
- 幼儿园健康教案《五官很重要》及教学反思
- 2025年运载火箭控制系统仿真实时处理系统合作协议书
- 后勤部门工作参考计划
- 2025年聚甲醛、聚甲醛合金及改性材料项目发展计划
- 大型型货车租赁合同书
- 特别赞助协议书
- 国际航运船只租赁合同
- 商场租赁合同书
- 2025年古马隆树脂项目建议书
- 2024年盾构操作工职业技能竞赛理论考试题库(含答案)
- (西北卷)名校教研联盟2025届高三12月联考英语试卷(含答案解析)
- 江苏省2025年高中学业水平合格考历史试卷试题(含答案详解)
- 大学试卷(示范)
- 高职院校智能制造实验室实训中心建设方案
- 房产交易管理平台行业发展预测分析
- 档案工作人员分工及岗位责任制(4篇)
- GB 4396-2024二氧化碳灭火剂
- 美丽的秋天景色作文500字小学
- 施工单位2025年度安全生产工作总结及计划
- 护理质量委员会会议
评论
0/150
提交评论