Android图片加载的缓存类
程序员文章站
2024-02-24 16:22:04
本文为大家分享了android图片加载的缓存类,供大家参考,具体内容如下
import java.io.file;
import java.io.filein...
本文为大家分享了android图片加载的缓存类,供大家参考,具体内容如下
import java.io.file; import java.io.fileinputstream; import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import java.lang.ref.softreference; import java.net.httpurlconnection; import java.net.url; import java.util.linkedhashmap; import java.util.concurrent.concurrenthashmap; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.os.build; import android.os.handler; import android.text.textutils; /** * 图片加载器,主要功能是从网络中下载图片并缓存。这里之所以另写一个功能类似重复的原因是 之前旧的图片加载逻辑感觉非常复杂,我这里写个轻量级的 * * @author h3c * */ public class imageloaderengine { public static final int load_img_success = 2010; private final int max_capacity = build.version.sdk_int > build.version_codes.gingerbread_mr1 ? 50 : 10;// 一级缓存缓存图片数 private static imageloaderengine instance; private static handler mhandler; private executorservice pool;// 后台线程池 // 这里用linkedhashmap不用lrucache的原因是lrucache直接申请内存大小而不是图片个数。此app已经有一个全局的lrucache了,重复申请内存大小对应用不利 private linkedhashmap<string, bitmap> mfirstlevelcache;// <momentid>一级缓存,硬链接bitmap,只保留最近用的图片。 private concurrenthashmap<string, softreference<bitmap>> msecondlevelcache;// <momentid> public static imageloaderengine getinstance(handler handler) { if (instance == null) { instance = new imageloaderengine(); } if(handler != null) { mhandler = handler; } return instance; } private imageloaderengine() { pool = executors.newfixedthreadpool(4);// 默认线程池大小为6 initcache(); } private void initcache() { mfirstlevelcache = new linkedhashmap<string, bitmap>(max_capacity / 2, 0.75f, true) { private static final long serialversionuid = 1l; protected boolean removeeldestentry(entry<string, bitmap> eldest) { if (size() > max_capacity) {// 超过一级缓存大小后会挪到二级缓存中 msecondlevelcache.put(eldest.getkey(), new softreference<bitmap>(eldest.getvalue())); return true; } return false; }; }; msecondlevelcache = new concurrenthashmap<string, softreference<bitmap>>();// <momentid> } /** * 移除缓存 * @param key */ public void deletecachebykey(string key) { string sdcacheingpath = iohelper.getcachedpicturepath( global.packagename, key); string sdcacheedpath = sdcacheingpath +".png"; file file = new file(sdcacheingpath); if(file.exists()) { file.delete(); } file = new file(sdcacheedpath); if(file.exists()) { file.delete(); } mfirstlevelcache.remove(key); msecondlevelcache.remove(key); } /** * 释放资源 */ public void recycleimageloader() { new thread(new runnable() { @override public void run() { if (pool != null) { pool.shutdownnow(); } if (mfirstlevelcache != null) { for (bitmap bmp : mfirstlevelcache.values()) { if (bmp != null) { bmp.recycle(); bmp = null; } } mfirstlevelcache.clear(); mfirstlevelcache = null; } if (msecondlevelcache != null) { msecondlevelcache.clear(); } mhandler = null; } }).start(); } /** * 后台请求图片 * * @param item */ public void loadimagebymoment(final nmoment moment,string phototag) { if (moment.ispicture() || moment.isvideo()) { string id = moment.id + phototag; loadimagebyurl(id+"", moment.getpicture(global.widthpixels/3*2),moment.orientation); } } /** * 后台请求图片 * @param key * @param url */ public void loadimagebyurl(final string key,final string url,final int orientation) { pool.submit(new runnable() { public void run() { loghelper.e("imageloaderengine","从网络中下载"); // 如果内存中有就算了 if (mfirstlevelcache.get(key) != null || msecondlevelcache.get(key) != null) {// 如果图片已经缓存了 loghelper.e("imageloaderengine","下载图片错误 1"); return; } // 如果sd卡缓存中有就算了 final string sdcacheingpath = iohelper.getcachedpicturepath( global.packagename, key); file cacheingfile = new file(sdcacheingpath); if (cacheingfile.exists()) {// 如果正在缓存就算了 long currenttime = system.currenttimemillis(); if((currenttime - cacheingfile.lastmodified()) >2 * 60 * 1000) { loghelper.e("imageloaderengine","2分钟都还没下载完,准备删除它.."+currenttime+"="+cacheingfile.lastmodified()); cacheingfile.delete(); } else { getbitmapfromnetworkandaddtomemory(url, key, orientation); loghelper.e("imageloaderengine","第二次进来应该走这里.."); return; } } string sdcacheedpath = sdcacheingpath + ".png";// 缓存完成后会改名字,否则会导致缓存错误,图片变黑 file cacheedfile = new file(sdcacheedpath); if (cacheedfile.exists()) {// 如果缓存了就算了 loghelper.e("imageloaderengine","下载图片错误 2"); return; } getbitmapfromnetworkandaddtomemory(url, key, orientation); } }); } private void getbitmapfromnetworkandaddtomemory(string url,string key,int orientation) { bitmap bmp = getbitmapfromurl(url); if(bmp!= null) { loghelper.e("imageloaderengine","下载网络图片成功"); if(key.endswith("_detaildaily")) { bmp = scaledbitmap(bmp, global.getthumbwidth()); } if(orientation != 0) { mfirstlevelcache.put(key, viewhelper.rotatebitmap(orientation, bmp));// 从网络下载后直接显示 } else { mfirstlevelcache.put(key, bmp);// 从网络下载后直接显示 } if (mhandler != null) { mhandler.removemessages(load_img_success); mhandler.sendemptymessagedelayed( load_img_success, 600);// 延时提示没有数据了 } final string sdcacheingpath = iohelper.getcachedpicturepath( global.packagename, key); savebitmaptofile(sdcacheingpath, bmp); } else { loghelper.e("imageloaderengine","下载网络图片失败..."); } } /** * 直接从网络中获取 * @param url * @return */ public bitmap getbitmapfromurl(string url) { url myfileurl = null; bitmap bitmap = null; inputstream is = null; try { if (!uiutils.isnetworkavailable(myapplication.getinstance())) { return null; } myfileurl = new url(url); httpurlconnection conn = (httpurlconnection) myfileurl .openconnection(); conn.setdoinput(true); conn.connect(); is = conn.getinputstream(); bitmap = bitmapfactory.decodestream(is); } catch (exception e) { try { if(is != null) { is.close(); } } catch (ioexception e1) { e1.printstacktrace(); } e.printstacktrace(); } return bitmap; } public bitmap getimageinmemory(nmoment moment) { return getimageinmemory(moment, ""); } /** * 新增接口,可以根据tag重新标识moment,这样可以扩展应用场景,比如首页需要大图,进入相集页需要小图 * @param moment * @param phototag * @return */ public bitmap getimageinmemory(nmoment moment, string phototag) { string id = moment.id + phototag; bitmap bmp = null; // 1. 从一级缓存中获取 bmp = getfromfirstlevelcache(id); if (bmp != null && !bmp.isrecycled()) { loghelper.e("imageloaderengine","一级缓存获取:"+id); return bmp; } // 2. 从二级缓存中获取 bmp = getfromsecondlevelcache(id); if (bmp != null && !bmp.isrecycled()) { loghelper.e("imageloaderengine","二级缓存获取:"+id); return bmp; } if(bmp != null && bmp.isrecycled()) { return null; } else { return bmp; } } public void setimage(string key,bitmap picture) { mfirstlevelcache.put(key, picture); } /** * 获取图片 */ public bitmap getimage(nmoment moment) { return getimage(moment, ""); } public bitmap getimage(nmoment moment, string phototag) { string id = moment.id + phototag; bitmap bmp = null; // 1. 从一级缓存中获取 bmp = getfromfirstlevelcache(id); if (bmp != null && !bmp.isrecycled()) { loghelper.e("imageloaderengine","一级缓存获取:"+id); return bmp; } // 2. 从二级缓存中获取 bmp = getfromsecondlevelcache(id); if (bmp != null && !bmp.isrecycled()) { loghelper.e("imageloaderengine","二级缓存获取:"+id); return bmp; } // 3. 从sd卡缓存中获取 bmp = getfromsdcache(moment, phototag); if (bmp != null && !bmp.isrecycled()) { loghelper.e("imageloaderengine","sd卡缓存获取:"+id); return bmp; } // 4. 从网络中获取 loadimagebymoment(moment, phototag); // loghelper.e("imageloaderengine","本地获取图片失败:"+moment.id+"="+moment.getpicture()); if(bmp != null && bmp.isrecycled()) { return null; } else { return bmp; } } public bitmap getimage(string key,string url) { bitmap bmp = null; // 1. 从一级缓存中获取 bmp = getfromfirstlevelcache(key); if (bmp != null && !bmp.isrecycled()) { return bmp; } // 2. 从二级缓存中获取 bmp = getfromsecondlevelcache(key); if (bmp != null && !bmp.isrecycled()) { return bmp; } // 3. 从sd卡缓存中获取 bmp = getfromsdcachebykey(key,0); if (bmp != null && !bmp.isrecycled()) { return bmp; } // 4. 从网络中获取 loadimagebyurl(key, url,0); if(bmp != null && bmp.isrecycled()) { return null; } else { return bmp; } } /** * 一级缓存获取图片 * * @param imgid * @return */ private bitmap getfromfirstlevelcache(string imgid) { bitmap bitmap = null; synchronized (mfirstlevelcache) { bitmap = mfirstlevelcache.get(imgid); if (bitmap != null) { mfirstlevelcache.remove(imgid); mfirstlevelcache.put(imgid, bitmap); } } return bitmap; } /** * 二级缓存获取图片 * * @param url * @return */ private bitmap getfromsecondlevelcache(string imgid) { bitmap bitmap = null; softreference<bitmap> softreference = msecondlevelcache.get(imgid); if (softreference != null) { bitmap = softreference.get(); if (bitmap == null) { msecondlevelcache.remove(imgid); } } return bitmap; } /** * 从sd卡缓存获取图片,并放入一级缓存中 * * @param moment * @return * @throws ioexception */ private bitmap getfromsdcache(final nmoment moment,final string phototag) { bitmap drawable = null; string id = moment.id + phototag; string sdcacheingpath = iohelper.getcachedpicturepath(global.packagename, id); string sdcacheedpath = sdcacheingpath + ".png"; if(moment.islocal){ if(moment.isvideo()) { //获取本地路径 sdcacheedpath = moment.getpicture(global.widthpixels/3*2); } else { sdcacheedpath = moment.local_res_path; } } file cachefile = new file(sdcacheedpath); if (!cachefile.exists()) {// 如果没有缓存完成就退出 loghelper.e("imageloaderengine","找不到缓存文件:"+sdcacheedpath); if(!textutils.isempty(moment.local_res_path)) {// 如果本地有图片,就先用本地图片代替 sdcacheedpath = moment.local_res_path; cachefile = new file(sdcacheedpath); if (cachefile.exists() && !globaldata.phone_manufacturer.equalsignorecase("samsung")) { loghelper.e("imageloaderengine","ak47...:"+globaldata.phone_manufacturer);// 先从本地找替代图片.. new thread(new runnable() {// 从网络下载 @override public void run() { loadimagebymoment(moment, phototag); } }).start(); return getfitphoto(sdcacheedpath, moment, cachefile); } else { return null; } } else { return null; } } drawable = getfitphoto(sdcacheedpath, moment, cachefile); if (drawable != null) { if (moment.orientation != 0) { drawable = viewhelper .rotatebitmap(moment.orientation, drawable); } if(mfirstlevelcache != null) { mfirstlevelcache.put(id, drawable); } } else { cachefile.delete(); } return drawable; } private bitmap getfitphoto(string sdcacheedpath,nmoment moment,file cachefile) { fileinputstream fs = null; bitmap result; try { bitmapfactory.options options = new bitmapfactory.options(); options.injustdecodebounds = true; bitmapfactory.decodefile(sdcacheedpath, options); int hratio = (int) math.ceil(options.outheight / (float) moment.picture_height); // 算高度 int wratio = (int) math.ceil(options.outwidth / (float) global.widthpixels); // 算宽度 if (hratio > 1 || wratio > 1) { if (hratio > wratio) { options.insamplesize = hratio; } else options.insamplesize = wratio; } options.inpurgeable = true; options.ininputshareable = true; options.indither = false; options.injustdecodebounds = false; try { fs = new fileinputstream(cachefile); } catch (filenotfoundexception e) { e.printstacktrace(); } result = bitmapfactory.decodefiledescriptor(fs.getfd(), null, options); } catch (exception e) { throw new runtimeexception(e); } finally { if (fs != null) { try { fs.close(); } catch (ioexception e) { e.printstacktrace(); } } } return result; } private bitmap getfromsdcachebykey(string key,int orientation) { bitmap drawable = null; fileinputstream fs = null; string sdcacheedpath = iohelper.getcachedpicturepath( global.packagename, key) + ".png"; file cachefile = new file(sdcacheedpath); if (!cachefile.exists()) {// 如果没有缓存完成就退出 return null; } try { bitmapfactory.options options = new bitmapfactory.options(); options.injustdecodebounds = true; bitmapfactory.decodefile(sdcacheedpath, options); int wratio = (int) math.ceil(options.outwidth / (float) global.widthpixels); // 算宽度 options.insamplesize = wratio; options.inpurgeable = true; options.ininputshareable = true; options.indither = false; options.injustdecodebounds = false; try { fs = new fileinputstream(cachefile); } catch (filenotfoundexception e) { e.printstacktrace(); } drawable = bitmapfactory.decodefiledescriptor(fs.getfd(), null, options); if (drawable != null) { if(orientation != 0) { drawable = viewhelper.rotatebitmap(orientation, drawable); } mfirstlevelcache.put(key, drawable); } else { cachefile.delete(); } } catch (exception e) { throw new runtimeexception(e); } finally { if (fs != null) { try { fs.close(); } catch (ioexception e) { e.printstacktrace(); } } } return drawable; } /** * 创建一个灰色的默认图 * @param moment * @return */ public bitmap getdefaultbitmap(nmoment moment) { return imagehelper.createbitmap(moment.picture_width, moment.picture_height, r.color.image_bg_daily); } /** * 保存bitmap文件到sd卡,传入jpg结尾的路径 * @param filepath * @param mbitmap */ public void savebitmaptofile(string filepath, bitmap mbitmap) { try { file file = new file(filepath); if (!file.getparentfile().exists()) { file.getparentfile().mkdirs(); } if (file.exists() && file.length() > 0) { long currenttime = system.currenttimemillis(); if ((currenttime - file.lastmodified()) > 2 * 60 * 1000) { loghelper.e("imageloaderengine", "2分钟都还没下载完,准备删除它.." + currenttime + "=" + file.lastmodified()); file.delete(); } else { return; } } else { file.createnewfile(); } fileoutputstream fout = null; fout = new fileoutputstream(file); mbitmap.compress(bitmap.compressformat.jpeg, 80, fout); fout.flush(); fout.close(); file.renameto(new file(filepath+".png")); } catch (exception e) { e.printstacktrace(); loghelper.e("imageloaderengine","保存图片错误:"+e); } loghelper.e("imageloaderengine","保存网络图片成功"+filepath+".png"); } /** * 保存文件至缓存,这里重写而不用iohelper里面的原因是iohelper里面过于复杂 * * @param url * @param filepath * @return */ public boolean saveurlbitmaptofile(string url, string filepath) { if (textutils.isempty(filepath)) { return false; } file iconfile = new file(filepath); if (iconfile.getparentfile() == null) { return false; } if (!iconfile.getparentfile().exists()) { iconfile.getparentfile().mkdirs(); } if (iconfile.exists() && iconfile.length() > 0) { long currenttime = system.currenttimemillis(); if((currenttime - iconfile.lastmodified()) >2 * 60 * 1000) { loghelper.e("imageloaderengine","2分钟都还没下载完,准备删除它.."+currenttime+"="+iconfile.lastmodified()); iconfile.delete(); } else { return true; } } fileoutputstream fos = null; inputstream is = null; try { fos = new fileoutputstream(filepath); is = new url(url).openstream(); int data = is.read(); while (data != -1) { fos.write(data); data = is.read(); } } catch (ioexception e) { loghelper.e("imageloaderengine", "imageloaderengine 下载图片错误" + e); iconfile.delete(); e.printstacktrace(); return false; } finally { try { if (is != null) { is.close(); } if (fos != null) { fos.close(); } } catch (ioexception e) { e.printstacktrace(); } } iconfile.renameto(new file(filepath+".png")); return true; } /** * 缩放bitmap * @param bmp * @param scaledvalue缩放值 * @return */ public bitmap scaledbitmap(bitmap bmp,int scaledvalue) { int bmpwidth = bmp.getwidth(); int bmpheight = bmp.getheight(); if(bmpwidth >= bmpheight) {// 横图 bmpwidth = (bmpwidth * scaledvalue / bmpheight); bmpheight = scaledvalue; } else { bmpheight = (bmpheight * scaledvalue / bmpwidth); bmpwidth = scaledvalue; } bitmap scaledbmp = bitmap.createscaledbitmap(bmp,bmpwidth,bmpheight,true); bmp.recycle(); bmp = null; return scaledbmp; } }
以上就是一个完整的android图片加载缓存类,希望对大家的学习有所帮助。
上一篇: 详解Java在redis中进行对象的缓存