图片的三级缓存基础
1.图片缓存优先级:Bitmap优于手机本地的图片文件优于服务器端的图片文件
一级缓存:内存缓存,缓存的是bitmap对象(这些对象在内存如何存储呢?一般而言有两种方式:List和Map,List根据下标来得到对象,Map根据Key得到对象,实际图片存储都是用Map)。
二级缓存:本地(SD卡)缓存,缓存的是图片文件,/storage/sdcard/Android/data/packageName/files/图片文件名(xxx.jpg)
三级缓存:远程服务器缓存,缓存的是图片文件,远程服务器上的应用中
2.如何使用三级缓存?-----如何根据图片的URL动态显示图片?
String imagePath = http://192.168.10.165:8080//L05_Web/images/f10.jpg和ImageView对象
1)。根据Url从一级缓存中取对应的bitmap对象
如果有,显示(结束)
如果没有,进入2
2)。从二级缓存中查找:得到文件名,并在sd卡的缓存目录下加载对应的图片得到Bitmap对象
如果有:显示,缓存到一级缓存中(结束)
如果没有,进入3
3)。显示代表提示正在加载的图片,启动分线程联网请求得到Bitmap对象
如果没有:显示提示错误的图片(结束)
如果有:
显示
缓存到一级缓存
缓存到二级缓存
1 /** 2 String iamgePath = http://192.168.10.165:8080//L05_Web/images/f10.jpg和ImageView对象 3 1). 根据url从一级缓存中取对应的bitmap对象 4 如果有, 显示(结束) 5 如果没有, 进入2) 6 2). 从二级缓存中查找: 得到文件名并在sd卡的缓存目录下加载对应的图片得到Bitmap对象 7 如果有: 显示, 缓存到一级缓存中(结束) 8 如果没有, 进入3) 9 3). 显示代表提示正在加载的图片, 启动分线程联网请求得到Bitmap对象 10 如果没有: 显示提示错误的图片(结束) 11 如果有: 12 显示 13 缓存到一级缓存 14 缓存到二级缓存 15 */ 16 public class ImageLoader { 17 18 private Context context; 19 private int loadingImageRes; 20 private int errorImageRes; 21 22 public ImageLoader(Context context, int loadingImageRes, int errorImageRes) { 23 super(); 24 this.context = context; 25 this.loadingImageRes = loadingImageRes; 26 this.errorImageRes = errorImageRes; 27 } 28 29 //用于缓存bitmap的容器对象 30 private Map<String, Bitmap> cacheMap = new HashMap<String, Bitmap>(); 31 32 /** 33 * 加载图片并显示 34 * @param imagePath 35 * @param imageView 36 */ 37 public void loadImage(String imagePath, ImageView imageView) { 38 39 //将需要显示的图片url保存到视图上 40 imageView.setTag(imagePath); 41 42 /* 43 1). 根据url从一级缓存中取对应的bitmap对象 44 如果有, 显示(结束) 45 如果没有, 进入2) 46 */ 47 Bitmap bitmap = getFromFirstCache(imagePath); 48 if(bitmap!=null) { 49 imageView.setImageBitmap(bitmap); 50 return; 51 } 52 /* 53 2). 从二级缓存中查找: 得到文件名并在sd卡的缓存目录下加载对应的图片得到Bitmap对象 54 如果有: 显示, 缓存到一级缓存中(结束) 55 如果没有, 进入3) 56 57 /storage/sdcard/Android/data/packageName/files/图片文件名(xxx.jpg) 58 */ 59 bitmap = getFromSecondCache(imagePath); 60 if(bitmap!=null) { 61 imageView.setImageBitmap(bitmap); 62 cacheMap.put(imagePath, bitmap); 63 return; 64 } 65 66 /* 67 3). 显示代表提示正在加载的图片, 启动分线程联网请求得到Bitmap对象 68 如果没有: 显示提示错误的图片(结束) 69 如果有: 70 缓存到一级缓存(分线程) 71 缓存到二级缓存(分线程) 72 显示(主线程) 73 74 */ 75 76 loadBitmapFromThirdCache(imagePath, imageView); 77 } 78 79 /** 80 * 根据图片url从三级缓存中取对应的bitmap对象并显示 81 * @param imagePath 82 * @param imageView 83 * AsyncTask 84 * loadBitmapFromThirdCache("../b.jpg", imageView) 85 * loadBitmapFromThirdCache("../f.jpg", imageView)--->imageView.setTag("../f.jpg") 86 */ 87 private void loadBitmapFromThirdCache(final String imagePath, final ImageView imageView) { 88 new AsyncTask<Void, Void, Bitmap>() { 89 protected void onPreExecute() { 90 imageView.setImageResource(loadingImageRes); 91 } 92 93 //联网请求得到bitmap对象 94 @Override 95 protected Bitmap doInBackground(Void... params) { 96 //在分线程执行, 可能需要等待一定时间才会执行 97 //在等待的过程中imageView中的tag值就有可能改变了 98 //如果改变了, 就不应该再去加载图片(此图片此时不需要显示) 99 100 Bitmap bitmap = null; 101 try { 102 103 //在准备请求服务器图片之前, 判断是否需要加载 104 String newImagePath = (String) imageView.getTag(); 105 if(newImagePath!=imagePath) {//视图已经被复用了 106 return null; 107 } 108 109 //得到连接 110 URL url = new URL(imagePath); 111 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 112 //设置 113 connection.setConnectTimeout(5000); 114 connection.setReadTimeout(5000); 115 //连接 116 connection.connect(); 117 //发请求读取返回的数据并封装为bitmap 118 int responseCode = connection.getResponseCode(); 119 if(responseCode==200) { 120 InputStream is = connection.getInputStream();//图片文件流 121 //将is封装为bitmap 122 bitmap = BitmapFactory.decodeStream(is); 123 is.close(); 124 125 if(bitmap!=null) { 126 //缓存到一级缓存(分线程) 127 cacheMap.put(imagePath, bitmap); 128 //缓存到二级缓存(分线程) 129 // /storage/sdcard/Android/data/packageName/files/ 130 String filesPath = context.getExternalFilesDir(null).getAbsolutePath(); 131 // http://192.168.10.165:8080//L05_Web/images/f10.jpg 132 String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);// f10.jpg 133 String filePath = filesPath+"/"+fileName; 134 bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(filePath)); 135 } 136 } 137 connection.disconnect(); 138 } catch (Exception e) { 139 e.printStackTrace(); 140 } 141 142 143 return bitmap; 144 } 145 146 protected void onPostExecute(Bitmap bitmap) {//从联网请求图片到得到图片对象需要一定的时间, 视图可能被复用了,不需要显示 147 //在主线程准备显示图片之前, 需要判断是否需要显示 148 String newImagePath = (String) imageView.getTag(); 149 if(newImagePath!=imagePath) {//视图已经被复用了 150 return; 151 } 152 153 //如果没有: 显示提示错误的图片(结束) 154 if(bitmap==null) { 155 imageView.setImageResource(errorImageRes); 156 } else {//如果有, 显示 157 imageView.setImageBitmap(bitmap); 158 } 159 } 160 }.execute(); 161 } 162 163 /** 164 * 根据图片url从二级缓存中取对应的bitmap对象 165 * @param imagePath 166 * @return 167 */ 168 private Bitmap getFromSecondCache(String imagePath) { 169 170 // /storage/sdcard/Android/data/packageName/files/ 171 String filesPath = context.getExternalFilesDir(null).getAbsolutePath(); 172 // http://192.168.10.165:8080//L05_Web/images/f10.jpg 173 String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);// f10.jpg 174 String filePath = filesPath+"/"+fileName; 175 176 return BitmapFactory.decodeFile(filePath); 177 } 178 179 /** 180 * 根据图片url从一级缓存中取对应的bitmap对象 181 * @param imagePath 182 * @return 183 */ 184 private Bitmap getFromFirstCache(String imagePath) { 185 return cacheMap.get(imagePath); 186 } 187 }
运行效果:
但是,图片一直在变换,并不固定。
视频学习地址:http://www.gulixueyuan.com/course/112/task/1732/show
图片三级缓存进阶:https://blog.csdn.net/lovoo/article/details/51456515