Android bitmap(五)完整例子ImageLoader

參考《android開發藝術探索》

1.圖片壓縮功能類ImageResizer

<pre>
public class ImageResizer{
private static final String TAG = "ImageResizer";

public ImageResizer(){
}

public Bitmap decodeSampledBitmapFromResource(Resource res,int resId,int reqWidth,int reqHeight){
//First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res,resId,options);
//calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
//decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res,resId,options);
}

public Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd,int reqWidth, int reqHeight){
//First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd,null,options);
//calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
//decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(fd,null,options);
}

public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
if(reqWidth == 0 || reqHeight == 0){
return 1;
}
//Raw height and width of image
final int width = options.outWidth;
final int height = options.outHeight;
Log.d(TAG,"origin,w="+width+"h="+height);
int inSampleSize = 1;

  if(height > reqHeight || width > reqWidth){
     final int halfHeight = height / 2;
     final int halfWidth = width / 2;
     while((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth){
        inSampleSize *= 2;
     }
  }
  Log.d(TAG,"sampleSize:"+inSampleSize);
  return inSampleSize;

}
}
</pre>

2.ImageLoader完整代碼

<pre>
public class ImageLoader{
private static final String TAG = "ImageLoader";
public static final int MESSAGE_POST_RESULT = 1;

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final long KEEP_ALIVE = 10L;

private static final int TAG_KEY_URI = R.id.imageloader_uri;
private static final long DISK_CACHE_SIZE = 1024 * 1024 * 50;
private static final int IO_BUFFER_SIZE = 8 * 1024;
private static final int DISK_CACHE_INDEX = 0;
private boolean mIsDiskLruCacheCreated = false;

private static final ThreadFactory sThreadFactory = new ThreadFactory(){
private final AtomicInteger mCount = new AtomicInteger(1);

  public Thread newThread(Runnable r){
     return new Thread(r, "ImageLoader#" + mCount.getAndIncrement());
  }

}

public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,TimeUnit.SECONDS,
new LinkedBlockingQueue<>(Runnable),sThreadFactory);

private Handler mMainHandler = new Handler(Looper.getMainLooper()){
public void handleMessage(Message msg){
LoaderResult result = (LoaderResult) msg.obj;
ImageView imageView = result.imageView;
String uri= (String) imageView.getTag(TAG_KEY_URI);
if(uri.equals(result.uri)){
imageView.setImageBitmap(result.bitmap);
}else{
Log.w(TAG,"set image bitmap,but url has changed,ignored!");
}
}
};

private Context mContext;
private ImageResizer mImageResizer = new ImageResizer();
private LruCache<String,Bitmap> mMemoryCache;
private DiskLruCache mDiskLruCache;

private ImageLoader(Context context){
mContext = context.getApplicationContext();
int maxMemory = (int) (Runtime.getRuntime().maxMemory / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize){
protected int sizeOf(String key,Bitmap bitmap){
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}
};
File diskCacheDir = getDiskCacheDir(mContext, "bitmap");
if(!diskCacheDir.exists()){
diskCacheDir.mkdirs();
}
if(getUsableSpace(diskCacheDir) > DISK_CACHE_SIZE){
try{
mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);
mIsDiskLruCacheCreated = true;
}catch(IOException e){
e.printStackTrace();
}
}
}

public static ImageLoader build(Context context){
return new ImageLoader(context);
}

private void addBitmapToMemoryCache(String key,Bitmap bitmap){
if(getBitmapFromMemCache(key) == null){
mMemoryCache.put(key, bitmap);
}
}

private Bitmap getBitmapFromMemCache(String key){
return mMemoryCache.get(key);
}

public void bindBitmap(final String uri, final ImageView imageView){
bindBitmap(uri,imageView,0,0);
}

/**
* load bitmap from memory cache or disk or network async,then bind imageview and bitmap
* NOTE THAT: should run in UI thread
*/
public void bindBitmap(final String uri, final ImageView imageView, final int reqWidth,final int reqHeight){
imageView.setTag(TAG_KEY_URI,uri);
Bitmap bitmap = loadBitmapFromMemCache(uri);
if(bitmap != null){
imageView.setImageBitmap(bitmap);
return;
}

  Runnable loadBitmapTask = new Runnable(){
     public void run(){
       Bitmap bitmap = loadBitmap(uri, reqWidth, reqHeight);
       if(bitmap != null){
          LoaderResult result = new LoaderResult(imageView,uri,bitmap);
          mMainHandler.obtainMessage(MESSAGE_POST_RESULT,result).sendToTarget();
       }
     }
  }
  THREAD_POOL_EXECUTOR.execute(loadBitmapTask);

}

public Bitmap loadBitmap(String uri,int reqWidth,int reqHeight){
Bitmap bitmap = loadBitmapFromMemCache(uri);
if(bitmap != null){
Log.d(TAG,"loadBitmapFromMemCache,url:"+uri);
return bitmap;
}

  try{
     bitmap = loadBitmapFromDiskCache(uri,reqWidth,reqHeight);
     if(bitmap != null){
        Log.d(TAG,"loadBitmapFromDiskCache,url:"+uri);
        return bitmap;
     }
     bitmap = loadBitmapFromHttp(uri,reqWidth,reqHeight);
     Log.d(TAG,"loadBitmapFromHttp,url:"+uri);
  }catch(IOException e){
     e.printStackTrace();
  }
  
  if(bitmap == null && !mIsDiskLruCacheCreated){
     Log.w(TAG, "encounter error,DiskLruCache is not created.");
     bitmap = downloadBitmapFromUrl(uri);
  }
  return bitmap;

}

private Bitmap loadBitmapFromMemCache(String url){
final String key = hashKeyFromUrl(url);
Bitmap bitmap = getBitmapFromMemCache(key);
return bitmap;
}

private Bitmap loadBitmapFromHttp(String url,int reqWidth, int reqHeight) throws IOException{
if(Looper.myLooper() == Looper.getMainLooper()){
throw new RuntimeException("can not visit network from UI Thread.");
}
if(mDiskLruCache == null){
return null;
}
String key = hashKeyFromUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if(editor != null){
OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
if(downloadUrlToStream(url,outputStream)){
editor.commit();
}else{
editor.abort();
}
mDiskLruCache.flush();
}
return loadBitmapFromDiskCache(url,reqWidth,reqHeight);
}

private Bitmap loadBitmapFromDiskCache(String url,int reqWidth,int reqHeight){
if(Looper.myLooper() == Looper.getMainLooper()){
Log.w(TAG,"load bitmap from UI Thread,it is not recommended!");
}
if(mDiskLruCache == null){
return null;
}

  Bitmap bitmap = null;
  String key = hashKeyFromUrl(url);
  DiskLruCache.SnapShot snapShot = mDiskLruCache.get(key);
  if(snapShot != null){
     FileInputStream fileInputStream = (FileInputStream)snapShot.getInputStream(DISK_CACHE_INDEX);
     FileDescriptor fileDescriptor = fileInputStream.getFD();
     bitmap = mImageResizer.decodeSampledBitmapFromFileDescriptor(fileDescriptor,reqWidth,reqHeight);
     if(bitmap != null){
        addBitmapToMemoryCache(key,bitmap);
     }
  }
  return bitmap;

}

public 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(),IO_BUFFER_SIZE);
out = new BufferedOutputStream(outputStream,IO_BUFFER_SIZE);
int b;
while((b = in.read()) != -1){
out.write(b);
}
return true;
}catch(IOException e){
Log.e(TAG,"downloadBitmap failed."+e);
}finally{
if(urlConnection != null){
urlConnection.disconnect();
}
MyUtils.close(out);
MyUtils.close(in);
}
return false;
}

private Bitmap downloadBitmapFromUrl(String urlString){
Bitmap bitmap = null;
HttpURLConnection urlConnection = null;
BufferedInputStream in = null;
try{
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(),IO_BUFFER_SIZE);
bitmap = BitmapFactory.decodeStream(in);
}catch(IOException e){
Log.e(TAG,"Error in downloadBitmap:"+e);
}finally{
if(urlConnection != null){
urlConnection.disconnect();
}
MyUtils.close(in);
}
return bitmap;
}

private String hashKeyFromUrl(String url){
String cacheKey;
try{
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(url.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
}catch(NoSuchAlgorithmException e){
cacheKey = String.valueOf(url.hasCode());
}
return cacheKey;
}

private String bytesToHexString(byte[] bytes){
StringBuilder sb = new StringBuilder();
for(int i = 0; i < bytes.length; i ++){
String hex = Integer.toHexString(0xFF & byte[i]);
if(hex.length() == 1){
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}

public File getDiskCacheDir(Context context,String uniqueName){
boolean externalStorageAvailable = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
final String cachePath;
if(externalStorageAvailable){
cachePath = context.getExternalCacheDir().getPath();
}else{
cachePath = context.getCacheDir().getPath();
}
return new File(cachePath + File.separator + uniqueName);
}

private long getUsableSpace(File path){
if(Build.VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD){
return path.getUsableSpace();
}
final StatFs stats = new StatFs(path.getPath());
return (long) stats.getBloackSize() * (long)stats.getAvailableBlocks();
}

private static class LoaderResult{
public ImageView imageView;
public String uri;
public Bitmap bitmap;

  public LoaderResult(ImageView imageView,String uri,Bitmap bitmap){
     this.imageView = imageView;
     this.uri = uri;
     this.bitmap = bitmap;
  }

}
}
</pre>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,727評論 25 708
  • 英語里面有一句“less is more”,我譯成少比多好。現在我覺得少即是多更好。源于今晚看到一張圖片順便分享給...
    A00Helen閱讀 176評論 0 0
  • 23種創新模式總署父文鏈接 享元模式的主要目的是實現對象的共享,即共享池,當系統中對象多的時候可以減少內存的開銷 ...
    風___________閱讀 283評論 0 0
  • 從沒深入考慮過類似的問題。而近期來,有了孩子,家里年事已高的老人也陸續步入了需要照顧的階段。突然疑惑了,太多人在對...
    珂望_閱讀 454評論 0 0