package com.buaa.shortytall.network; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; 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.HashMap; import java.util.LinkedHashMap; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.params.HttpClientParams; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.util.EntityUtils; import com.buaa.shortytall.MyHealth; import com.buaa.shortytall.thread.GlobalMultiThreadExecutor; import com.buaa.shortytall.util.MD5Util; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.os.Handler; import android.os.StatFs; import android.text.TextUtils; public class ImageCache { private LinkedHashMap<String, SoftReference<Bitmap>> memCache; private HashMap<String,String> urlMap; private static ImageCache instance; private static String IMAGE_FILE_FOLDER_PATH = MyHealth.APP_SDCARD_FOLDER + "/MyHealth/.imagcecache/"; private static final int MB = 1024 * 1024; private static final int TIMEOUT = 3000; private static boolean STORAGE_ON = false; private Handler handler; private DefaultHttpClient mHttpClient = null; // static{ // if(mHttpClient == null){ // mHttpClient = new DefaultHttpClient(); // } // } //lock for url map private Object urlMapLock = new Object(); //image fresh lock private boolean freshImgWaiting = false; /** * 计算sd空间 * @return sd空间大小 M */ public int freeSpaceOnSd(){ StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); double sdFreeMB = ((double)stat.getAvailableBlocks()*(double)stat.getBlockSize()) / MB; return (int)sdFreeMB; } static{ if (instance == null){ instance = new ImageCache(); } //sdcard prepared if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ File file = new File(IMAGE_FILE_FOLDER_PATH); if (!file.exists()){ file.mkdirs(); } STORAGE_ON = true; } } private ImageCache(){ memCache = new LinkedHashMap<String, SoftReference<Bitmap>>(); urlMap = new HashMap<String, String>(); } public static ImageCache getInstance(){ return instance; } public Bitmap getBitmapFromUrl(String url){ Bitmap bitmap = getCachedBitmap(url); //this means if bitmap is in cache , this is no need to get bitmap from url if (bitmap != null){ return bitmap; } synchronized (urlMapLock) { //if urlMap is in, this bitmap is working for getting if (urlMap.containsKey(url)){ return null; }else{ urlMap.put(url, url); } } GlobalMultiThreadExecutor.getInstance().execute(new FetchImageRunnable(url), Thread.MIN_PRIORITY); return null; } private Bitmap getBitmapFromSDCard(String url){ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { Bitmap bmp; String filePathStr = IMAGE_FILE_FOLDER_PATH + MD5Util.encodeByMD5(url) + ".png"; File file = new File(filePathStr); if (!file.exists()) { return null; } FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(file); bmp = BitmapFactory.decodeStream(fileInputStream); return bmp; } catch (Exception e) { return null; } finally { try { fileInputStream.close(); } catch (Exception e) { } } } else { return null; } } private class FetchImageRunnable implements Runnable{ private String url; public FetchImageRunnable(String url){ this.url = url; } @Override public void run() { Bitmap bitmap = null; bitmap = getBitmapFromSDCard(url); if (bitmap == null){ bitmap = getBitmapFromUrlBackground(url); } if (bitmap != null){ handler.post(new BitmapFreshRunnable(url,bitmap)); } } } private class BitmapFreshRunnable implements Runnable{ private String mUrl; private Bitmap mBitmap; public BitmapFreshRunnable(String url,Bitmap bitmap){ this.mUrl = url; this.mBitmap = bitmap; } @Override public void run() { if (!TextUtils.isEmpty(mUrl) && mBitmap != null ){ memCache.put(mUrl, new SoftReference<Bitmap>(mBitmap)); if (freshImgWaiting){ return ; } freshImgWaiting = true; handler.postDelayed(new Runnable() { @Override public void run() { handler.sendEmptyMessage(MyHealth.Msg.IMG_LOADED_COMPLETED); freshImgWaiting = false; } }, 100); } } } /** * 下载图片,以字节数组返 */ public static byte[] downLoadImage(String path) throws Exception { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5 * 1000); InputStream inStream = conn.getInputStream(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[100 * 1024]; int len = -1; while ((len = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, len); } outStream.close(); inStream.close(); return outStream.toByteArray(); } @SuppressWarnings("unused") private byte[] fetchImg(HttpGet httpGet){ //Http HttpParams params = new BasicHttpParams(); HttpConnectionParams.setSoTimeout(params, TIMEOUT); HttpConnectionParams.setConnectionTimeout(params, TIMEOUT); HttpClientParams.setRedirecting(params, true); if (mHttpClient == null){ mHttpClient = new DefaultHttpClient(); } mHttpClient.setParams(params); try { HttpResponse response = mHttpClient.execute(httpGet); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ HttpEntity entity = response.getEntity(); byte[] imgbytes = EntityUtils.toByteArray(entity); //this method means entity is no longer need entity.consumeContent(); return imgbytes; } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private Bitmap getBitmapFromUrlBackground(String url){ //do cache File file = new File(IMAGE_FILE_FOLDER_PATH + MD5Util.encodeByMD5(url) + ".png"); if (file.exists()){ Bitmap filebitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); if (filebitmap != null){ synchronized (urlMapLock) { urlMap.remove(url); } return filebitmap; }else{ file.delete(); } } byte[] imgbytes = null; try { imgbytes = downLoadImage(url); } catch (Exception e1) { e1.printStackTrace(); } if (imgbytes == null){ return null; } Bitmap bitmap = BitmapFactory.decodeByteArray(imgbytes, 0, imgbytes.length); if (STORAGE_ON){ try { FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(imgbytes); fileOutputStream.flush(); fileOutputStream.close(); return bitmap; } catch (IOException e) { e.printStackTrace(); synchronized (urlMapLock) { urlMap.remove(url); } } }else { synchronized (urlMapLock) { urlMap.remove(url); } } return null; } public void setHandler(Handler handler){ this.handler = handler; } public Bitmap getCachedBitmap(String Url){ SoftReference<Bitmap> bitmap = memCache.get(Url); if (bitmap != null){ Bitmap cachedBitmap = bitmap.get(); if (cachedBitmap == null){ memCache.remove(Url); urlMap.remove(Url); } return cachedBitmap; } return null; } }