国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Android圖片加載:采用二級緩存、異步加載網絡圖片

移動開發 Android
Android應用中經常涉及從網絡中加載大量圖片,為提升加載速度和效率,減少網絡流量都會采用二級緩存和異步加載機制,所謂二級緩存就是通過先從內存中獲取、再從文件中獲取,最后才會訪問網絡。

一、問題描述

Android應用中經常涉及從網絡中加載大量圖片,為提升加載速度和效率,減少網絡流量都會采用二級緩存和異步加載機制,所謂二級緩存就是通過先從內存中獲取、再從文件中獲取,***才會訪問網絡。內存緩存(一級)本質上是Map集合以key-value對的方式存儲圖片的url和Bitmap信息,由于內存緩存會造成堆內存泄露, 管理相對復雜一些,可采用第三方組件,對于有經驗的可自己編寫組件,而文件緩存比較簡單通常自己封裝一下即可。下面就通過案例看如何實現網絡圖片加載的優化。

二、案例介紹

案例新聞的列表圖片

三、主要核心組件

下面先看看實現一級緩存(內存)、二級緩存(磁盤文件)所編寫的組件

1、MemoryCache

在內存中存儲圖片(一級緩存), 采用了1個map來緩存圖片代碼如下:

  1. public class MemoryCache { 
  2. // ***的緩存數 
  3. private static final int MAX_CACHE_CAPACITY = 30
  4. //用Map軟引用的Bitmap對象, 保證內存空間足夠情況下不會被垃圾回收 
  5. private HashMap<String, SoftReference<Bitmap>> mCacheMap = 
  6. new LinkedHashMap<String, SoftReference<Bitmap>>() { 
  7. private static final long serialVersionUID = 1L; 
  8. //當緩存數量超過規定大?。ǚ祷豻rue)會清除最早放入緩存的 
  9. protected boolean removeEldestEntry( 
  10. Map.Entry<String,SoftReference<Bitmap>> eldest){ 
  11. return size() > MAX_CACHE_CAPACITY;}; 
  12. }; 
  13.  
  14. /** 
  15. * 從緩存里取出圖片 
  16. * @param id 
  17. * @return 如果緩存有,并且該圖片沒被釋放,則返回該圖片,否則返回null 
  18. */ 
  19. public Bitmap get(String id){ 
  20. if(!mCacheMap.containsKey(id)) return null
  21. SoftReference<Bitmap> ref = mCacheMap.get(id); 
  22. return ref.get(); 
  23.  
  24. /** 
  25. * 將圖片加入緩存 
  26. * @param id 
  27. * @param bitmap 
  28. */ 
  29. public void put(String id, Bitmap bitmap){ 
  30. mCacheMap.put(id, new SoftReference<Bitmap>(bitmap)); 
  31. /** 
  32. * 清除所有緩存 
  33. */ 
  34. public void clear() { 
  35. try { 
  36. for(Map.Entry<String,SoftReference<Bitmap>>entry :mCacheMap.entrySet()) 
  37. { SoftReference<Bitmap> sr = entry.getValue(); 
  38. if(null != sr) { 
  39. Bitmap bmp = sr.get(); 
  40. if(null != bmp) bmp.recycle(); 
  41. mCacheMap.clear(); 
  42. catch (Exception e) { 
  43. e.printStackTrace();} 
2、FileCache

在磁盤中緩存圖片(二級緩存),代碼如下

  1. public class FileCache { 
  2. //緩存文件目錄 
  3. private File mCacheDir; 
  4. /** 
  5. * 創建緩存文件目錄,如果有SD卡,則使用SD,如果沒有則使用系統自帶緩存目錄 
  6. * @param context 
  7. * @param cacheDir 圖片緩存的一級目錄 
  8. */ 
  9. public FileCache(Context context, File cacheDir, String dir){ 
  10. if(android.os.Environment.getExternalStorageState().equals、(android.os.Environment.MEDIA_MOUNTED)) 
  11. mCacheDir = new File(cacheDir, dir); 
  12. else 
  13. mCacheDir = context.getCacheDir();// 如何獲取系統內置的緩存存儲路徑 
  14. if(!mCacheDir.exists()) mCacheDir.mkdirs(); 
  15. public File getFile(String url){ 
  16. File f=null
  17. try { 
  18. //對url進行編輯,解決中文路徑問題 
  19. String filename = URLEncoder.encode(url,"utf-8"); 
  20. f = new File(mCacheDir, filename); 
  21. catch (UnsupportedEncodingException e) { 
  22. e.printStackTrace(); 
  23. return f; 
  24. public void clear(){//清除緩存文件 
  25. File[] files = mCacheDir.listFiles(); 
  26. for(File f:files)f.delete(); 

3、編寫異步加載組件AsyncImageLoader

android中采用單線程模型即應用運行在UI主線程中,且Android又是實時操作系統要求及時響應否則出現ANR錯誤,因此對于耗時操作要求不能阻塞UI主線程,需要開啟一個線程處理(如本應用中的圖片加載)并將線程放入隊列中,當運行完成后再通知UI主線程進行更改,同時移除任務——這就是異步任務,在android中實現異步可通過本系列一中所用到的AsyncTask或者使用thread+handler機制,在這里是完全是通過代碼編寫實現的,這樣我們可以更清晰的看到異步通信的實現的本質,代碼如下

  1. public class AsyncImageLoader{ 
  2. private MemoryCache mMemoryCache;//內存緩存 
  3. private FileCache mFileCache;//文件緩存 
  4. private ExecutorService mExecutorService;//線程池 
  5. //記錄已經加載圖片的ImageView 
  6. private Map<ImageView, String> mImageViews = Collections 
  7. .synchronizedMap(new WeakHashMap<ImageView, String>()); 
  8. //保存正在加載圖片的url 
  9. private List<LoadPhotoTask> mTaskQueue = new ArrayList<LoadPhotoTask>(); 
  10. /** 
  11. * 默認采用一個大小為5的線程池 
  12. * @param context 
  13. * @param memoryCache 所采用的高速緩存 
  14. * @param fileCache 所采用的文件緩存 
  15. */ 
  16. public AsyncImageLoader(Context context, MemoryCache memoryCache, FileCache fileCache) { 
  17. mMemoryCache = memoryCache; 
  18. mFileCache = fileCache; 
  19. mExecutorService = Executors.newFixedThreadPool(5);//建立一個容量為5的固定尺寸的線程池(***正在運行的線程數量) 
  20. /** 
  21. * 根據url加載相應的圖片 
  22. * @param url 
  23. * @return 先從一級緩存中取圖片有則直接返回,如果沒有則異步從文件(二級緩存)中取,如果沒有再從網絡端獲取 
  24. */ 
  25. public Bitmap loadBitmap(ImageView imageView, String url) { 
  26. //先將ImageView記錄到Map中,表示該ui已經執行過圖片加載了 
  27. mImageViews.put(imageView, url); 
  28. Bitmap bitmap = mMemoryCache.get(url);//先從一級緩存中獲取圖片 
  29. if(bitmap == null) { 
  30. enquequeLoadPhoto(url, imageView);//再從二級緩存和網絡中獲取 
  31. return bitmap; 
  32.  
  33. /** 
  34. * 加入圖片下載隊列 
  35. * @param url 
  36. */ 
  37. private void enquequeLoadPhoto(String url, ImageView imageView) { 
  38. //如果任務已經存在,則不重新添加 
  39. if(isTaskExisted(url)) 
  40. return
  41. LoadPhotoTask task = new LoadPhotoTask(url, imageView); 
  42. synchronized (mTaskQueue) { 
  43. mTaskQueue.add(task);//將任務添加到隊列中 
  44. mExecutorService.execute(task);//向線程池中提交任務,如果沒有達到上限(5),則運行否則被阻塞 
  45.  
  46. /** 
  47. * 判斷下載隊列中是否已經存在該任務 
  48. * @param url 
  49. * @return 
  50. */ 
  51. private boolean isTaskExisted(String url) { 
  52. if(url == null
  53. return false
  54. synchronized (mTaskQueue) { 
  55. int size = mTaskQueue.size(); 
  56. for(int i=0; i<size; i++) { 
  57. LoadPhotoTask task = mTaskQueue.get(i); 
  58. if(task != null && task.getUrl().equals(url)) 
  59. return true
  60. return false
  61.  
  62. /** 
  63. * 從緩存文件或者網絡端獲取圖片 
  64. * @param url 
  65. */ 
  66. private Bitmap getBitmapByUrl(String url) { 
  67. File f = mFileCache.getFile(url);//獲得緩存圖片路徑 
  68. Bitmap b = ImageUtil.decodeFile(f);//獲得文件的Bitmap信息 
  69. if (b != null)//不為空表示獲得了緩存的文件 
  70. return b; 
  71. return ImageUtil.loadBitmapFromWeb(url, f);//同網絡獲得圖片 
  72.  
  73. /** 
  74. * 判斷該ImageView是否已經加載過圖片了(可用于判斷是否需要進行加載圖片) 
  75. * @param imageView 
  76. * @param url 
  77. * @return 
  78. */ 
  79. private boolean imageViewReused(ImageView imageView, String url) { 
  80. String tag = mImageViews.get(imageView); 
  81. if (tag == null || !tag.equals(url)) 
  82. return true
  83. return false
  84.  
  85. private void removeTask(LoadPhotoTask task) { 
  86. synchronized (mTaskQueue) { 
  87. mTaskQueue.remove(task); 
  88.  
  89. class LoadPhotoTask implements Runnable { 
  90. private String url; 
  91. private ImageView imageView; 
  92. LoadPhotoTask(String url, ImageView imageView) { 
  93. this.url = url; 
  94. this.imageView = imageView; 
  95.  
  96. @Override 
  97. public void run() { 
  98. if (imageViewReused(imageView, url)) {//判斷ImageView是否已經被復用 
  99. removeTask(this);//如果已經被復用則刪除任務 
  100. return
  101. Bitmap bmp = getBitmapByUrl(url);//從緩存文件或者網絡端獲取圖片 
  102. mMemoryCache.put(url, bmp);// 將圖片放入到一級緩存中 
  103. if (!imageViewReused(imageView, url)) {//若ImageView未加圖片則在ui線程中顯示圖片 
  104. BitmapDisplayer bd = new BitmapDisplayer(bmp, imageView, url); Activity a = (Activity) imageView.getContext(); 
  105. a.runOnUiThread(bd);//在UI線程調用bd組件的run方法,實現為ImageView控件加載圖片 
  106. removeTask(this);//從隊列中移除任務 
  107. public String getUrl() { 
  108. return url; 
  109.  
  110. /** 
  111. * 
  112. *由UI線程中執行該組件的run方法 
  113. */ 
  114. class BitmapDisplayer implements Runnable { 
  115. private Bitmap bitmap; 
  116. private ImageView imageView; 
  117. private String url; 
  118. public BitmapDisplayer(Bitmap b, ImageView imageView, String url) { 
  119. bitmap = b; 
  120. this.imageView = imageView; 
  121. this.url = url; 
  122. public void run() { 
  123. if (imageViewReused(imageView, url)) 
  124. return
  125. if (bitmap != null
  126. imageView.setImageBitmap(bitmap); 
  127.  
  128. /** 
  129. * 釋放資源 
  130. */ 
  131. public void destroy() { 
  132. mMemoryCache.clear(); 
  133. mMemoryCache = null
  134. mImageViews.clear(); 
  135. mImageViews = null
  136. mTaskQueue.clear(); 
  137. mTaskQueue = null
  138. mExecutorService.shutdown(); 
  139. mExecutorService = null

編寫完成之后,對于異步任務的執行只需調用AsyncImageLoader中的loadBitmap()方法即可非常方便,對于AsyncImageLoader組件的代碼***結合注釋好好理解一下,這樣對于Android中線程之間的異步通信就會有深刻的認識。

4、工具類ImageUtil

  1. public class ImageUtil { 
  2. /** 
  3. * 從網絡獲取圖片,并緩存在指定的文件中 
  4. * @param url 圖片url 
  5. * @param file 緩存文件 
  6. * @return 
  7. */ 
  8. public static Bitmap loadBitmapFromWeb(String url, File file) { 
  9. HttpURLConnection conn = null
  10. InputStream is = null
  11. OutputStream os = null
  12. try { 
  13. Bitmap bitmap = null
  14. URL imageUrl = new URL(url); 
  15. conn = (HttpURLConnection) imageUrl.openConnection(); 
  16. conn.setConnectTimeout(30000); 
  17. conn.setReadTimeout(30000); 
  18. conn.setInstanceFollowRedirects(true); 
  19. is = conn.getInputStream(); 
  20. os = new FileOutputStream(file); 
  21. copyStream(is, os);//將圖片緩存到磁盤中 
  22. bitmap = decodeFile(file); 
  23. return bitmap; 
  24. catch (Exception ex) { 
  25. ex.printStackTrace(); 
  26. return null
  27. finally { 
  28. try { 
  29. if(os != null) os.close(); 
  30. if(is != null) is.close(); 
  31. if(conn != null) conn.disconnect(); 
  32. catch (IOException e) { } 
  33.  
  34. public static Bitmap decodeFile(File f) { 
  35. try { 
  36. return BitmapFactory.decodeStream(new FileInputStream(f), nullnull); 
  37. catch (Exception e) { } 
  38. return null
  39. private static void copyStream(InputStream is, OutputStream os) { 
  40. final int buffer_size = 1024
  41. try { 
  42. byte[] bytes = new byte[buffer_size]; 
  43. for (;;) { 
  44. int count = is.read(bytes, 0, buffer_size); 
  45. if (count == -1
  46. break
  47. os.write(bytes, 0, count); 
  48. catch (Exception ex) { 
  49. ex.printStackTrace(); 

四、測試應用

組件之間的時序圖:

1、編寫MainActivity

  1. public class MainActivity extends Activity { 
  2. ListView list; 
  3. ListViewAdapter adapter; 
  4. @Override 
  5. public void onCreate(Bundle savedInstanceState) { 
  6. super.onCreate(savedInstanceState); 
  7. setContentView(R.layout.main); 
  8. list=(ListView)findViewById(R.id.list); 
  9. adapter=new ListViewAdapter(this, mStrings); 
  10. list.setAdapter(adapter); 
  11. public void onDestroy(){ 
  12. list.setAdapter(null); 
  13. super.onDestroy(); 
  14. adapter.destroy(); 
  15. private String[] mStrings={ 
  16. "http://news.21-sun.com/UserFiles/x_Image/x_20150606083511_0.jpg"
  17. "http://news.21-sun.com/UserFiles/x_Image/x_20150606082847_0.jpg"
  18. …..}; 
  19. }

2、編寫適配器

  1. public class ListViewAdapter extends BaseAdapter { 
  2. private Activity mActivity; 
  3. private String[] data; 
  4. private static LayoutInflater inflater=null
  5. private AsyncImageLoader imageLoader;//異步組件 
  6.  
  7. public ListViewAdapter(Activity mActivity, String[] d) { 
  8. this.mActivity=mActivity; 
  9. data=d; 
  10. inflater = (LayoutInflater)mActivity.getSystemService( 
  11. Context.LAYOUT_INFLATER_SERVICE); 
  12. MemoryCache mcache=new MemoryCache();//內存緩存 
  13. File sdCard = android.os.Environment.getExternalStorageDirectory();//獲得SD卡 
  14. File cacheDir = new File(sdCard, "jereh_cache" );//緩存根目錄 
  15. FileCache fcache=new FileCache(mActivity, cacheDir, "news_img");//文件緩存 
  16. imageLoader = new AsyncImageLoader(mActivity, mcache,fcache); 
  17. public int getCount() { 
  18. return data.length; 
  19. public Object getItem(int position) { 
  20. return position; 
  21. public long getItemId(int position) { 
  22. return position; 
  23.  
  24. public View getView(int position, View convertView, ViewGroup parent) { 
  25. ViewHolder vh=null
  26. if(convertView==null){ 
  27. convertView = inflater.inflate(R.layout.item, null); 
  28. vh=new ViewHolder(); 
  29. vh.tvTitle=(TextView)convertView.findViewById(R.id.text); 
  30. vh.ivImg=(ImageView)convertView.findViewById(R.id.image); 
  31. convertView.setTag(vh); 
  32. }else
  33. vh=(ViewHolder)convertView.getTag(); 
  34. vh.tvTitle.setText("標題信息測試———— "+position); 
  35. vh.ivImg.setTag(data[position]); 
  36. //異步加載圖片,先從一級緩存、再二級緩存、***網絡獲取圖片 
  37. Bitmap bmp = imageLoader.loadBitmap(vh.ivImg, data[position]); 
  38. if(bmp == null) { 
  39. vh.ivImg.setImageResource(R.drawable.default_big); 
  40. else { 
  41. vh.ivImg.setImageBitmap(bmp); 
  42. return convertView; 
  43. private class ViewHolder{ 
  44. TextView tvTitle; 
  45. ImageView ivImg; 
  46. public void destroy() { 
  47. imageLoader.destroy(); 
責任編輯:chenqingxiang 來源: 博客園
相關推薦

2009-06-18 15:24:35

Hibernate二級

2013-06-27 11:16:27

Android異步加載

2013-09-08 23:30:56

EF Code Fir架構設計MVC架構設計

2009-09-21 14:59:31

Hibernate二級

2009-09-24 11:04:56

Hibernate二級

2009-09-21 14:39:40

Hibernate二級

2009-09-21 13:31:10

Hibernate 3

2013-10-16 16:58:17

iOS優化緩存優化

2009-09-23 09:37:07

Hibernate緩存

2009-06-10 15:00:58

Hibernate二級配置

2025-04-29 07:06:20

2017-11-08 14:34:20

圖片fresco程序員

2009-08-13 18:12:12

Hibernate 3

2024-12-03 14:38:07

CaffeineRedis二級緩存

2022-12-02 12:01:30

Spring緩存生命周期

2022-03-01 18:03:06

Spring緩存循環依賴

2022-01-12 07:48:19

緩存Spring 循環

2025-06-26 01:55:00

2023-04-27 08:18:10

MyBatis緩存存儲

2010-01-27 17:53:18

Android顯示網絡
點贊
收藏

51CTO技術棧公眾號

国产精品一二三视频| 欧美性做爰猛烈叫床潮| 91国产在线精品| missav|免费高清av在线看| 中文字幕在线播放不卡一区| 欧美乱大交xxxxx潮喷l头像| 久久久噜噜噜久久狠狠50岁| 亚洲综合大片69999| 国产中文精品久高清在线不| 久久亚洲一区二区三区四区五区高| 黄色av网站在线播放| 日本乱码高清不卡字幕| 在线免费观看高清视频色| 亚洲欧美一区二区三区国产精品 | 国产精品系列在线播放| 黄色网zhan| 亚洲精品黑牛一区二区三区| 精品区一区二区| 久久国产精品-国产精品| 你懂的好爽在线观看| 在线成人中文字幕| 岛国av在线播放| 亚洲人成电影在线观看天堂色| 日韩精品在线观看av| 日韩电影一二三区| 日韩片电影在线免费观看| 日韩成人一级片| 国产精品免费看久久久无码| 成人av资源网站| 男操女免费网站| 国产在线高清理伦片a| 亚洲国产一区二区a毛片| 在线资源av| 欧洲亚洲国产日韩| 新版中文在线官网| 亚洲天堂男人的天堂| 国产精品久久久久久久app | 亚洲深深色噜噜狠狠爱网站| www.久久爱.com| 最近2019中文字幕mv免费看 | 日韩中文一区| 日本在线不卡视频一二三区| 亚洲v欧美v另类v综合v日韩v| 国产真实乱对白精彩久久| 欧美牲交a欧美牲交aⅴ免费下载| 国产欧美综合色| 小香蕉视频在线| 日韩欧美激情一区| 曰本一区二区| 国产欧美亚洲精品| 久久中文欧美| 久久久久久久久久久免费视频| 亚洲另类在线视频| 女人天堂在线| 亚洲一级免费视频| 久久久伦理片| 精品国产一区二区三区四区精华| 国精产品一区一区三区mba视频| 欧美久久久精品| 欧美激情电影| 在线观看欧美亚洲| 1区2区3区精品视频| 成人在线app| 欧美高清在线观看| 99av国产精品欲麻豆| 搞av.com| 一本色道a无线码一区v| 日韩在线影院| 国产视频999| 激情亚洲综合在线| 亚洲超碰在线| 国产一区二区三区直播精品电影| 蜜桃a∨噜噜一区二区三区| 日本视频精品一区| 亚洲欧洲综合另类| 国产网站在线| av影院在线播放| 久久久久久久久99精品大| 日韩妆和欧美的一区二区| 99久久国产免费看| 999在线视频| 欧美极品欧美精品欧美视频| 亚洲久久一区| 国产成人a亚洲精v品无码| 欧美精品在线视频| 国产探花在线精品| 人妻激情另类乱人伦人妻| 五月婷婷欧美视频| 在线免费观看亚洲| 欧美精品在线一区| 亚洲综合色噜噜狠狠| 黄页免费欧美| 日本10禁啪啪无遮挡免费一区二区| 亚洲女同一区二区| 91福利精品在线观看| 久久久久久久久久久久久久一区| 亚洲男人的天堂一区二区| 嫩草伊人久久精品少妇av杨幂| 国产一区二区三区奇米久涩| 日本一区二区三区久久久久久久久不| 国精产品一区一区三区mba下载| 成人久久久久久久| 中文字幕一区二区三| 久久亚洲精品人成综合网| 精品在线观看一区二区| 亚洲最新视频在线观看| 欧美视频精品全部免费观看| 日韩aⅴ视频一区二区三区| 色中色一区二区| 欧美aaaaaaaa牛牛影院| 美女福利视频在线| 亚洲视频在线播放| 韩日精品视频| 久久免费大视频| 久久一卡二卡| 乱码第一页成人| 日本视频二区| 久久久久亚洲精品| 老司机精品视频导航| 国产网友自拍视频导航网站在线观看| 欧美亚洲一级片| 国产精品久久免费看| 亚洲精品成人一区| 免费成人午夜视频| 国产一区二区三区精品久久久| 青青草成人在线观看| 天堂中文8资源在线8| www成人在线观看| 国产精品1luya在线播放| 国产精品久久婷婷六月丁香| japanese23hdxxxx日韩| 欧美精品亚洲精品| 日本道在线观看一区二区| 欧美男gay| av高清日电影| 性日韩欧美在线视频| 国产欧美日产一区| 亚洲成人五区| 亚洲少妇第一页| 久久99国产精品自在自在app| 成人少妇影院yyyy| 成人在线黄色| 免费在线观看亚洲视频| 久久香蕉国产线看观看网| 91在线视频观看| 久久久91麻豆精品国产一区| 亚洲乱码国产一区三区| 欧美理论片在线观看| 中文字幕一区二区三区在线不卡 | 337p粉嫩大胆噜噜噜噜噜91av | 欧美日韩国产成人在线免费| 国产亚洲在线观看| 麻豆影视国产在线观看| 欧美日韩成人一区二区三区| 欧美一区二区视频在线观看2022| 中文亚洲欧美| 综合久久2023| 可以在线看的黄色网址| 欧美激情乱人伦一区| 亚洲乱码日产精品bd| 一区二区三区在线电影| 国产三级在线播放| 裸体大乳女做爰69| 久久久久亚洲精品成人网小说| 国产精品久久久久久妇女6080| 综合色就爱涩涩涩综合婷婷| 免费在线超碰| 日本不卡一区二区三区四区| 欧美猛交免费看| 欧美日韩精品在线视频| 欧美aaaaaaa| 国产高清www| 国产成人+综合亚洲+天堂| 欧美性做爰猛烈叫床潮| 久久精品99久久久| 日韩精品三级| 九色视频在线播放| 日本大胆人体视频| 日本精品视频在线| 911精品国产一区二区在线| 成人性色生活片| 日本久久精品| 欧美激情网站| 国产午夜在线| 日韩啊v在线| 欧美性色黄大片| 国产精一品亚洲二区在线视频| 奇米影视777在线欧美电影观看 | 亚洲成人激情综合网| 99在线精品视频在线观看| 久久久精品一区二区毛片免费看| 免费一级大片| 亚洲国产高清国产精品| 538国产精品一区二区免费视频 | 久久精品国产成人精品| 天天操天天色综合| 国产成人鲁色资源国产91色综| 四虎成人av| 欧美电影免费观看| 中文字幕免费在线|