1.圖片的三級緩存策略
1.內(nèi)存緩存:優(yōu)先加載,速度最快
2.本地緩存:次優(yōu)先級加載,速度次之,
3.網(wǎng)絡(luò)緩存:最后加載,速度由網(wǎng)速決定
2.內(nèi)存緩存
首先創(chuàng)建一個MemoryCacheUtils類,內(nèi)存緩存一般使用LruChche緩存策略,首先需要或者應(yīng)用可用的最大內(nèi)存,然后設(shè)置緩存的可用大小,將圖片的緩存大小設(shè)為最大緩存的1/8或者1/4,應(yīng)在初始化中調(diào)用,因此
public MemoryCacheUtils(){
? ? long maxMemory = Runtime.getRuntime().maxMemory();//獲取最大內(nèi)存,一般默認(rèn)是16MB
? ? //獲取圖片字節(jié)數(shù)
? ? mLruCache = new LruCache((int)maxMemory/8){
? ? ? ? @Override
? ? ? ? protected int sizeOf(String key, Bitmap value) {
? ? ? ? ? ? //獲取圖片字節(jié)數(shù)
? ? ? ? ? ? int byteCount = value.getRowBytes() * value.getWidth();
? ? ? ? ? ? return byteCount;
? ? ? ? }
? ? };
}
內(nèi)存緩存中對圖片的保存和讀取十分簡單
//從內(nèi)存中獲取圖片
public Bitmap getBitmapFormMemory(String url){
? ? return mLruCache.get(url);
}
//將圖片保存在內(nèi)存中
public void saveBitmap2Memory(String url, Bitmap bitmap){
? ? mLruCache.put(url, bitmap);
}
3.本地緩存
本地緩存首先需要獲取SD卡的根目錄的路徑
public static final String CACHE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()+"/imagememory/";
圖片的保存
首先以Url作為關(guān)鍵字對圖片進(jìn)行保存,在保存時需要對Url進(jìn)行MD5加密,將加密后返回的字符串作為關(guān)鍵字創(chuàng)建文件夾,同時保存圖片
public void saveBitmap2SD(String url, Bitmap bitmap){
? ? //對文件地址進(jìn)行MD5加密
? ? String fileName = null;
? ? try {
? ? ? ? fileName = MD5Encoder.encode(url);
? ? } catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? }
? ? File file = new File(CACHE_PATH, fileName);
? ? File parentFile = file.getParentFile();
? ? if (!parentFile.exists()){
? ? ? ? parentFile.mkdirs();
? ? }
? ? try {
? ? ? ? //將圖片保存到本地
? ? ? ? bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(file));
? ? } catch (FileNotFoundException e){
? ? ? ? e.printStackTrace();
? ? }
}
圖片的讀取
從SD卡中讀取圖片,首先也需要將傳入的Url進(jìn)行加密并將返回的字符串作為索引,查找對應(yīng)的文件夾中,通過BitmapFactory.decodeStream獲得bitmap
public Bitmap getImageFormSD(String url){
? ? //對文件地址進(jìn)行MD5加密
? ? String fileName = null;
? ? try {
? ? ? ? fileName = MD5Encoder.encode(url);
? ? } catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? }
? ? File file = new File(CACHE_PATH, fileName);
? ? if (file.exists()){
? ? ? ? Bitmap bitmap;
? ? ? ? try {
? ? ? ? ? ? bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
? ? ? ? ? ? return bitmap;
? ? ? ? } catch (FileNotFoundException e){
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? return null;
}
4.網(wǎng)絡(luò)緩存圖片
網(wǎng)絡(luò)緩存圖片時需要將網(wǎng)絡(luò)獲得的圖片緩存到內(nèi)存和SD卡中,因此需要在構(gòu)造方法中初始化內(nèi)存緩存工具類和SD卡緩存工具類
public NetCacheUtils(SDcardCacheUtils sDcardCacheUtils, MemoryCacheUtils memoryCacheUtils){
? ? mSDcardCacheUtils = sDcardCacheUtils;
? ? mMemoryCacheUtils = memoryCacheUtils;
}
從網(wǎng)絡(luò)中獲取圖片是一個耗時操作,因此這里采用AsyncTask異步棧的方式實現(xiàn)圖片的異步下載,因此就需要自定義一個MyAsyncTask繼承與AsyncTask
class MyAsyncTask extends AsyncTask{
? ? @Override
? ? protected Bitmap doInBackground(Object... objects) {
? ? ? ? //拿到傳入的iamge
? ? ? ? mImageView = (ImageView)objects[0];
? ? ? ? mUrl = (String)objects[1];
? ? ? ? mImageView.setTag(mUrl);
? ? ? ? Bitmap bitmap = downloadBitmap(mUrl);
? ? ? ? return bitmap;
? ? }
? ? @Override
? ? protected void onPostExecute(Bitmap bitmap) {
? ? ? ? if (bitmap != null){
? ? ? ? ? ? String url = (String) mImageView.getTag();
? ? ? ? ? ? if (url.equals(mUrl)){
? ? ? ? ? ? ? ? mImageView.setImageBitmap(bitmap);
? ? ? ? ? ? ? ? mMemoryCacheUtils.saveBitmap2Memory(url, bitmap);
? ? ? ? ? ? ? ? mSDcardCacheUtils.saveBitmap2SD(url, bitmap);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
private Bitmap downloadBitmap(String url) {
? ? HttpURLConnection connection = null;
? ? try {
? ? ? ? connection = (HttpURLConnection) new URL(url).openConnection();
? ? ? ? connection.setReadTimeout(5000);
? ? ? ? connection.setRequestMethod("GET");
? ? ? ? connection.setConnectTimeout(5000);
? ? ? ? connection.connect();
? ? ? ? int code = connection.getResponseCode();
? ? ? ? if (code == 200){
? ? ? ? ? ? InputStream inputStream = connection.getInputStream();
? ? ? ? ? ? Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
? ? ? ? ? ? return bitmap;
? ? ? ? }
? ? } catch (IOException e){
? ? ? ? e.printStackTrace();
? ? } finally {
? ? ? ? connection.disconnect();
? ? }
? ? return null;
}
5.大圖片的加載
1.首先需要拿到位圖的尺寸后,進(jìn)行放縮后再加載位圖
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream();
int imageWidth = options.outWidth;
int iamgeHight = options.outHeight;
String imageType = options.outMimeType;
2.計算inSampleSize
public static int calculateInSampleZSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
? ? int width = options.outWidth;
? ? int height = options.outHeight;
? ? int inSampleSize = 1;
? ? if (height>reqHeight || width>reqWidth){
? ? ? ? int halfHeight = height / 2;
? ? ? ? int halfWidth = width / 2;
? ? ? ? while ((halfHeight/inSampleSize)>reqHeight && (halfWidth/inSampleSize)>reqWidth){
? ? ? ? ? ? inSampleSize *= 2;
? ? ? ? }
? ? }
? ? return inSampleSize;
}
3.放縮后再加載小位圖
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resid, int reqWidth, int reqHeight){
? ? BitmapFactory.Options options = new BitmapFactory.Options();
? ? options.inJustDecodeBounds = true;
? ? BitmapFactory.decodeResource(res,resid, options);
? ? options.inSampleSize = calculateInSampleZSize(options,reqWidth, reqHeight);
? ? options.inJustDecodeBounds= false;
? ? return BitmapFactory.decodeResource(res,resid,options);
}