Android二级缓存加载图片实现照片墙功能
程序员文章站
2022-08-08 08:55:13
实现二级缓存加载图片的功能,在使用disklrucache时,需先在工程中添加名为libcore.io的包,并将disklrucache.java文件放进去。disklru...
实现二级缓存加载图片的功能,在使用disklrucache时,需先在工程中添加名为libcore.io的包,并将disklrucache.java文件放进去。disklrucache直接百度下载即可。
在gridview的适配器中,为imageview添加图片时,先从内存缓存中加载,内存中无缓存的话则在磁盘缓存中加载,磁盘缓存也没有的话开启线程下载,然后将下载的图片缓存到磁盘,内存中。下载的图片最好先进行压缩,文章最后给出了压缩代码,但本例中并未实现压缩。
/*二级缓存实现图片墙功能,先在内存中加载缓存,内存中无缓存的话到磁盘缓存中加载,仍然没有的话开启线程下载图片,下载后缓存到磁盘中,然后缓存到内存中*/
public class erjihuancun extends arrayadapter<string> { /** * 记录所有正在下载或等待下载的任务。 */ private set<bitmapworkertask> taskcollection; /** * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。 */ private lrucache<string, bitmap> mmemorycache; /** * 图片硬盘缓存核心类。 */ private disklrucache mdisklrucache; /** * gridview的实例 */ private gridview mphotowall; /** * 记录每个子项的高度。 */ private int mitemheight = 0; public erjihuancun(context context, int textviewresourceid, string[] objects, gridview photowall) { super(context, textviewresourceid, objects); mphotowall = photowall; taskcollection = new hashset<bitmapworkertask>(); // 获取应用程序最大可用内存 int maxmemory = (int) runtime.getruntime().maxmemory(); int cachesize = maxmemory / 8; // 设置图片缓存大小为程序最大可用内存的1/8 mmemorycache = new lrucache<string, bitmap>(cachesize) { @override protected int sizeof(string key, bitmap bitmap) { return bitmap.getbytecount(); } }; try { // 获取图片缓存路径 file cachedir = getdiskcachedir(context, "thumb"); if (!cachedir.exists()) { cachedir.mkdirs(); } // 创建disklrucache实例,初始化缓存数据 mdisklrucache = disklrucache .open(cachedir, getappversion(context), 1, 10 * 1024 * 1024); } catch (ioexception e) { e.printstacktrace(); } } @override public view getview(int position, view convertview, viewgroup parent) { final string url = getitem(position); view view; if (convertview == null) { view = layoutinflater.from(getcontext()).inflate(r.layout.photo_layout, null); } else { view = convertview; } final imageview imageview = (imageview) view.findviewbyid(r.id.photo); if (imageview.getlayoutparams().height != mitemheight) { imageview.getlayoutparams().height = mitemheight; } // 给imageview设置一个tag,保证异步加载图片时不会乱序 imageview.settag(url); imageview.setimageresource(r.drawable.ic_launcher); loadbitmaps(imageview, url); return view; } /** * 将一张图片存储到lrucache中。 * * @param key * lrucache的键,这里传入图片的url地址。 * @param bitmap * lrucache的键,这里传入从网络上下载的bitmap对象。 */ public void addbitmaptomemorycache(string key, bitmap bitmap) { if (getbitmapfrommemorycache(key) == null) { mmemorycache.put(key, bitmap); } } /** * 从lrucache中获取一张图片,如果不存在就返回null。 * * @param key * lrucache的键,这里传入图片的url地址。 * @return 对应传入键的bitmap对象,或者null。 */ public bitmap getbitmapfrommemorycache(string key) { return mmemorycache.get(key); } /** * 加载bitmap对象。此方法会在lrucache中检查所有屏幕中可见的imageview的bitmap对象, * 如果发现任何一个imageview的bitmap对象不在缓存中,就会开启异步线程去下载图片。 */ public void loadbitmaps(imageview imageview, string imageurl) { try { bitmap bitmap = getbitmapfrommemorycache(imageurl); if (bitmap == null) { bitmapworkertask task = new bitmapworkertask(); taskcollection.add(task); task.execute(imageurl); } else { if (imageview != null && bitmap != null) { imageview.setimagebitmap(bitmap); } } } catch (exception e) { e.printstacktrace(); } } /** * 取消所有正在下载或等待下载的任务。 */ public void cancelalltasks() { if (taskcollection != null) { for (bitmapworkertask task : taskcollection) { task.cancel(false); } } } /** * 根据传入的uniquename获取硬盘缓存的路径地址。 */ public file getdiskcachedir(context context, string uniquename) { string cachepath; if (environment.media_mounted.equals(environment.getexternalstoragestate()) || !environment.isexternalstorageremovable()) { cachepath = context.getexternalcachedir().getpath(); } else { cachepath = context.getcachedir().getpath(); } return new file(cachepath + file.separator + uniquename); } /** * 获取当前应用程序的版本号。 */ public int getappversion(context context) { try { packageinfo info = context.getpackagemanager().getpackageinfo(context.getpackagename(), 0); return info.versioncode; } catch (namenotfoundexception e) { e.printstacktrace(); } return 1; } /** * 设置item子项的高度。 */ public void setitemheight(int height) { if (height == mitemheight) { return; } mitemheight = height; notifydatasetchanged(); } /** * 使用md5算法对传入的key进行加密并返回。 */ public string hashkeyfordisk(string key) { string cachekey; try { final messagedigest mdigest = messagedigest.getinstance("md5"); mdigest.update(key.getbytes()); cachekey = bytestohexstring(mdigest.digest()); } catch (nosuchalgorithmexception e) { cachekey = string.valueof(key.hashcode()); } return cachekey; } /** * 将缓存记录同步到journal文件中。 */ public void flushcache() { if (mdisklrucache != null) { try { mdisklrucache.flush(); } catch (ioexception e) { e.printstacktrace(); } } } private string bytestohexstring(byte[] bytes) { stringbuilder sb = new stringbuilder(); for (int i = 0; i < bytes.length; i++) { string hex = integer.tohexstring(0xff & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.tostring(); } /** * 异步下载图片的任务。 * * */ class bitmapworkertask extends asynctask<string, void, bitmap> { /** * 图片的url地址 */ private string imageurl; @override protected bitmap doinbackground(string... params) { imageurl = params[0]; filedescriptor filedescriptor = null; fileinputstream fileinputstream = null; snapshot snapshot = null; try { // 生成图片url对应的key final string key = hashkeyfordisk(imageurl); // 查找key对应的缓存 snapshot = mdisklrucache.get(key); if (snapshot == null) { // 如果没有找到对应的缓存,则准备从网络上请求数据,并写入缓存 disklrucache.editor editor = mdisklrucache.edit(key); if (editor != null) { outputstream outputstream = editor.newoutputstream(0); if (downloadurltostream(imageurl, outputstream)) { editor.commit(); } else { editor.abort(); } } // 缓存被写入后,再次查找key对应的缓存 snapshot = mdisklrucache.get(key); } if (snapshot != null) { fileinputstream = (fileinputstream) snapshot.getinputstream(0); filedescriptor = fileinputstream.getfd(); } // 将缓存数据解析成bitmap对象 bitmap bitmap = null; if (filedescriptor != null) { // bitmap = bitmapfactory.decodefiledescriptor(filedescriptor); windowmanager wm= (windowmanager)getcontext().getsystemservice(context.window_service); int width=wm.getdefaultdisplay().getwidth(); bitmap= imageresizer.decodesamplebithmapfromfiledescriptor(filedescriptor,width/3,width/3); } if (bitmap != null) { // 将bitmap对象添加到内存缓存当中 addbitmaptomemorycache(params[0], bitmap); } return bitmap; } catch (ioexception e) { e.printstacktrace(); } finally { if (filedescriptor == null && fileinputstream != null) { try { fileinputstream.close(); } catch (ioexception e) { } } } return null; } @override protected void onpostexecute(bitmap bitmap) { super.onpostexecute(bitmap); // 根据tag找到相应的imageview控件,将下载好的图片显示出来。 imageview imageview = (imageview) mphotowall.findviewwithtag(imageurl); if (imageview != null && bitmap != null) { imageview.setimagebitmap(bitmap); } taskcollection.remove(this); } /** * 建立http请求,并获取bitmap对象。 * * @param imageurl * 图片的url地址 * @return 解析后的bitmap对象 */ private boolean downloadurltostream(string urlstring, outputstream outputstream) { httpurlconnection urlconnection = null; bufferedoutputstream out = null; bufferedinputstream in = null; try { final url url = new url(urlstring); urlconnection = (httpurlconnection) url.openconnection(); in = new bufferedinputstream(urlconnection.getinputstream(), 8 * 1024); out = new bufferedoutputstream(outputstream, 8 * 1024); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (final ioexception e) { e.printstacktrace(); } finally { if (urlconnection != null) { urlconnection.disconnect(); } try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (final ioexception e) { e.printstacktrace(); } } return false; } } }
mainactivity
/** * 照片墙主活动,使用gridview展示照片墙。 * * */ public class mainactivity extends activity { /** * 用于展示照片墙的gridview */ private gridview mphotowall; /** * gridview的适配器 */ private erjihuancun madapter; private int mimagethumbsize; private int mimagethumbspacing; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); //mimagethumbsize = getresources().getdimensionpixelsize( // r.dimen.image_thumbnail_size); //mimagethumbspacing = getresources().getdimensionpixelsize( // r.dimen.image_thumbnail_spacing); mphotowall = (gridview) findviewbyid(r.id.photo_wall); madapter = new erjihuancun(this, 0, images.imagethumburls, mphotowall); mphotowall.setadapter(madapter); /* mphotowall.getviewtreeobserver().addongloballayoutlistener( new viewtreeobserver.ongloballayoutlistener() { @override public void ongloballayout() { final int numcolumns = (int) math.floor(mphotowall .getwidth() / (mimagethumbsize + mimagethumbspacing)); if (numcolumns > 0) { int columnwidth = (mphotowall.getwidth() / numcolumns) - mimagethumbspacing; madapter.setitemheight(columnwidth); mphotowall.getviewtreeobserver() .removeglobalonlayoutlistener(this); } } });*/ } @override protected void onpause() { super.onpause(); //将缓存记录同步到journal文件中 madapter.flushcache(); } @override protected void ondestroy() { super.ondestroy(); // // 退出程序时结束所有的下载任务 madapter.cancelalltasks(); } }
/** * 自定义正方形的imageview * */ public class myimageview extends imageview { public myimageview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); // todo auto-generated constructor stub } public myimageview(context context, attributeset attrs) { super(context, attrs); // todo auto-generated constructor stub } public myimageview(context context) { super(context); // todo auto-generated constructor stub } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { // todo auto-generated method stub //将高度信息改成宽度即可 super.onmeasure(widthmeasurespec, widthmeasurespec); } }
主activity的layout
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" > <gridview android:id="@+id/photo_wall" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:horizontalspacing="5dp" android:verticalspacing="5dp" android:numcolumns="3" android:stretchmode="columnwidth" /> </linearlayout>
gridview中的item imageview
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.example.imageloader.myimageview android:layout_width="match_parent" android:layout_height="0dp" android:id="@+id/photo" /> </linearlayout>
图片压缩实现
public class imageresizer { private static final string tag="imageresizer"; public static bitmap decodesampledbitmapfromresource(resources res, int resid,int reqwidth,int reqheight){ final bitmapfactory.options options=new bitmapfactory.options(); options.injustdecodebounds=true; bitmapfactory.decoderesource(res,resid,options); options.insamplesize=calculateinsamplesize(options,reqwidth,reqheight); options.injustdecodebounds=false; return bitmapfactory.decoderesource(res, resid, options); } public static bitmap decodesamplebithmapfromfiledescriptor(filedescriptor fd, int reqwidth,int reqheight){ final bitmapfactory.options options=new bitmapfactory.options(); options.injustdecodebounds=true; bitmapfactory.decodefiledescriptor(fd, null,options); options.insamplesize=calculateinsamplesize(options,reqwidth,reqheight); options.injustdecodebounds=false; return bitmapfactory.decodefiledescriptor(fd, null,options); } public static int calculateinsamplesize(bitmapfactory.options options, int reqwidth,int reqheight){ if(reqwidth==0||reqheight==0) return 1; final int width=options.outwidth; final int height=options.outheight; int insamplesize=1; if(height>reqheight||width>reqwidth ){ final int halfheight=height/2; final int halfwidth=width/2; //尽最大限度的压缩图片,不能让图片的宽高比imageview的宽高小,否则在将 //图片显示到imageview时,图片会放大导致图片失真 while(halfheight/insamplesize>reqheight&&halfwidth/insamplesize>reqwidth){ insamplesize*=2; } } return insamplesize; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: php安装grpc扩展的具体步骤
下一篇: 初恋回来复合怎么处理