非同步下載圖片+圖片快取
阿新 • • 發佈:2019-02-14
程式碼參考自:jamendo,有一定修改。
功能如下:
流程如下:
RemoteImageViewActivity:
public class RemoteImageViewActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); RemoteImageView img = (RemoteImageView) findViewById(R.id.remote_img); img.setDefaultImage(R.drawable.ic_launcher); img.setImageUrl("http://img2.kwcdn.kuwo.cn:81/star/albumcover/120/7/8/83787_1323997225.jpg"); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); } }
ImageCache:
public class ImageCache extends WeakHashMap<String, Bitmap>{
/**
* 判斷該url是否存在
* @param url
* @return
*/
public boolean isCached(String url){
return containsKey(url) && get(url) != null;
}
}
RemoteImageApplication:
public class RemoteImageApplication extends Application { public static final String TAG = "RemoteImageApplication"; private static RemoteImageApplication application; private ImageCache mImageCache; public SharedPreferences prefs = null; public static RemoteImageApplication getInstance() { return application; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); application = this; mImageCache = new ImageCache(); prefs = PreferenceManager.getDefaultSharedPreferences(this); } public ImageCache getImageCache() { return mImageCache; } }
RemoteSettings:
public class RemoteSettings {
public static final String CACHE_SIZE = "cache_size"; //圖片快取保留大小,如果超過該大小,即進行自動清除快取.
}
RemoteImageView:
public class RemoteImageView extends ImageView { private Context mContext; private static int mCacheSize = 150; // 設定的快取大小。 private static final int MAX_FAILURES = 3; // 下載的嘗試請求次數 private int mFailure; // 下載失敗次數 private String mUrl; // 當前下載的url private String mCurrentlyGrabbedUrl; // 當前下載成功的url private final static String JAMENDO_DIR = "Android/data/com.teleca.jamendo"; // 檔案快取存放的路徑. private final static long MB = 1073741824; public RemoteImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mContext = context; } public RemoteImageView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; } public RemoteImageView(Context context) { super(context); mContext = context; } /** * 設定預設圖片 */ public void setDefaultImage(Integer resid) { setImageResource(resid); } /** * 設定需要非同步載入的圖片 */ public void setImageUrl(String url) { // 下載失敗進行重試,如果重試次數超過規定的限制,則直接返回. if (mUrl != null && mUrl.equals(url) && (mCurrentlyGrabbedUrl == null || (mCurrentlyGrabbedUrl != null && !mCurrentlyGrabbedUrl .equals(url)))) { mFailure++; if (mFailure > MAX_FAILURES) { Log.e(RemoteImageApplication.TAG, "下載該圖片地址失敗:" + url); return; } } else { mUrl = url; mFailure = 0; } ImageCache imageCache = RemoteImageApplication.getInstance() .getImageCache(); if (imageCache.isCached(url)) { setImageBitmap(imageCache.get(url)); } else { // 如果記憶體中沒有該快取,則從檔案中進行查詢. String fileName = convertUrlToFileName(url); // 進行檔名處理 String filepath = getDirectory(fileName); // 取得快取資料夾目錄 String pathFileName = filepath + "/" + fileName; // 組拼檔案 File pathFile = new File(pathFileName); if (!pathFile.exists()) { try { pathFile.createNewFile(); } catch (IOException e) { Log.d(RemoteImageApplication.TAG, "建立圖片檔案失敗:" + pathFileName); } } Bitmap tbmp = BitmapFactory.decodeFile(pathFileName); if (tbmp == null) { Log.d(RemoteImageApplication.TAG, "圖片檔案不存在,開始進行下載"); try { new DownloadTask().execute(url); } catch (RejectedExecutionException e) { Log.d(RemoteImageApplication.TAG, "下載失敗"); } } else { Log.i(RemoteImageApplication.TAG, "從檔案中載入圖片"); RemoteImageApplication.getInstance().getImageCache() .put(url, tbmp); this.setImageBitmap(tbmp); } updateCacheSize(pathFileName); // 進行檢測檔案大小,以便於清除快取. } } private void updateCacheSize(String pathFileName) { // TODO Auto-generated method stub updateSizeCache(pathFileName); } /** * 檢查檔案目錄是否超過規定的快取大小 * * @param fileName */ private void updateSizeCache(String pathFileName) { // TODO Auto-generated method stub mCacheSize = PreferenceManager.getDefaultSharedPreferences(mContext) .getInt(RemoteSettings.CACHE_SIZE, 100); // 讀取設定的快取大小,前臺可以動態設定此值 if (isSDCardEnable()) { String extStorageDirectory = Environment .getExternalStorageDirectory().toString(); // 取得SD根路徑 String dirPath = extStorageDirectory + "/" + JAMENDO_DIR + "/imagecache"; File dirFile = new File(dirPath); File[] files = dirFile.listFiles(); long dirSize = 0; for (File file : files) { dirSize += file.length(); } if (dirSize > mCacheSize * MB) { clearCache(); } } } /** * 非同步下載圖片 * * @ClassName: DownloadTask * @author 姜濤 * @version 1.0 2012-1-15 下午5:06:21 */ class DownloadTask extends AsyncTask<String, Void, String> { private String mTaskUrl; private Bitmap mBmp = null; @Override public void onPreExecute() { // loadDefaultImage(); super.onPreExecute(); } @Override public String doInBackground(String... params) { mTaskUrl = params[0]; InputStream stream = null; URL imageUrl; Bitmap bmp = null; try { imageUrl = new URL(mTaskUrl); try { stream = imageUrl.openStream(); bmp = BitmapFactory.decodeStream(stream); try { if (bmp != null) { mBmp = bmp; RemoteImageApplication.getInstance() .getImageCache().put(mTaskUrl, bmp); Log.d(RemoteImageApplication.TAG, "圖片快取到application中: " + mTaskUrl); } } catch (NullPointerException e) { Log.w(RemoteImageApplication.TAG, "下載失敗,圖片為空:" + mTaskUrl); } } catch (IOException e) { Log.w(RemoteImageApplication.TAG, "無法載入該url:" + mTaskUrl); } finally { try { if (stream != null) { stream.close(); } } catch (IOException e) { } } } catch (MalformedURLException e) { e.printStackTrace(); } return mTaskUrl; } @Override public void onPostExecute(String url) { super.onPostExecute(url); Bitmap bmp = RemoteImageApplication.getInstance().getImageCache() .get(url); if (bmp == null) { Log.w(RemoteImageApplication.TAG, "嘗試重新下載:" + url); RemoteImageView.this.setImageUrl(url); } else { RemoteImageView.this.setImageBitmap(bmp); mCurrentlyGrabbedUrl = url; saveBmpToSd(mBmp, url); } } }; /** * 把圖片儲存到本地 * * @param bm * @param url */ private void saveBmpToSd(Bitmap bm, String url) { if (bm == null) { return; } if (mCacheSize == 0) { return; } String filename = convertUrlToFileName(url); String dir = getDirectory(filename); File file = new File(dir + "/" + filename); try { file.createNewFile(); OutputStream outStream = new FileOutputStream(file); bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream); outStream.flush(); outStream.close(); Log.i(RemoteImageApplication.TAG, "圖片已儲存到sd卡"); } catch (FileNotFoundException e) { Log.w(RemoteImageApplication.TAG, "無法找到檔案目錄"); } catch (IOException e) { Log.w(RemoteImageApplication.TAG, "操作檔案出錯"); } } /** * 組拼檔名,字尾名用dat代替,避免別人使用圖片管理器搜尋出這種對於她們無用的圖片. * * @param url * @return */ private String convertUrlToFileName(String url) { String filename = url; filename = filename.replace("http://", ""); filename = filename.replace("/", "."); filename = filename.replace(":", "."); filename = filename.replace("jpg", "dat"); filename = filename.replace("png", "dat"); return filename; } /** * 返回快取圖片所存放的資料夾 * * @param filename * @return */ private String getDirectory(String filename) { String extStorageDirectory = Environment.getExternalStorageDirectory() .toString(); // 取得SD根路徑 String dirPath = extStorageDirectory + "/" + JAMENDO_DIR + "/imagecache"; File dirFile = new File(dirPath); if (!dirFile.exists()) { dirFile.mkdirs(); } return dirPath; } /** * 清除快取 */ private void clearCache() { if (isSDCardEnable()) { String extStorageDirectory = Environment .getExternalStorageDirectory().toString(); // 取得SD根路徑 String dirPath = extStorageDirectory + "/" + JAMENDO_DIR + "/imagecache"; File dir = new File(dirPath); File[] files = dir.listFiles(); // 取得該目錄下的所有檔案 if (files == null || files.length == 0) { return; } for (File file : files) { file.delete(); } Log.d(RemoteImageApplication.TAG, "已清除快取:" + dirPath); } } /** * 判斷SD卡是否可用 */ public static boolean isSDCardEnable() { return Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED); } }
程式碼參見附件.