日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Bitmap Cache

發布時間:2025/3/21 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Bitmap Cache 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

譯文出自谷歌安卓官網圖片緩存篇

  • 緩存位圖
  • 使用內存緩存Use a Memory Cache
  • 使用磁盤緩存Use a Disk Cache
  • 處理配置發生改變的情況Handle Configuration Changes

緩存位圖

加載一個簡單的位圖到UI中比較快,但是如果加載一些大的位圖的話,則會變得很復雜。在許多情況下(ListView,GridView,ViewPager),屏幕上的圖片與即將滾動到屏幕上的圖片個數一般是無限制的。通過回收移除屏幕外的子視圖可以讓內存使用率降下來。假設你不做任何長引用的話,垃圾收集器也會釋放你已加載的位圖。一切都很好,但是如果你想要保持一個流動的并快速加載的UI的話,你必須避免重復加載這些即將滾動回屏幕的圖片。內存緩存與磁盤緩存可以做到這些,允許組件快速加載已處理過的圖片。

使用內存緩存(Use a Memory Cache)

內存緩存以占用應用程序一些內存為條件提供了快速獲取位圖的方式。LruCache類被用來做緩存圖片任務的,讓最近引用的對象保存到強引用LinkedHashMap中,并在超出緩存大小之前刪除最近最少使用的成員。
注意:在過去,流行的內存緩存實現是SoftReference 或 WeakReference位圖緩存,但是現在不推薦使用了。從Android2.3開始,垃機回收器會更喜歡回收soft/weak references,這導致了它們變得無效了。除此之外,在Android3.0之前,備份的位圖數據被保存在本地內存中,釋放方式是不可預測的,可能導致應用程序快速的超過內存限制并導致崩潰。

為了選擇合適的LruCache大小,一些因素我們需要考慮:

  • Activity或者Application剩余內存
  • 多少張圖片會立即顯示到屏幕上,還有多少會滾動到屏幕中。
  • 設備的屏幕大小與密度,像Galaxy Nexus這種高分辨率xhdpi比起Nexus S來說,需要更大的緩存。
  • Bitmap的大小與類型決定單張圖片所需內存大小
  • 圖片獲取的頻率,哪些圖片獲取的更頻繁,如果這樣,你可能需要將固定的某些圖片放入內存中,或者為多組Bitmap分配多個LruCache
  • 質量與數量之間衡量,有時候后臺加載高質量的圖片的時候,我們存儲低質量的圖片更好一些。

Android沒有指定固定的大小與格式用于適合所有應用程序,它完全由你自己去分析使用并提出合適的解決方案。緩存太小毫無用處并造成負擔,緩存過大可能會引起java.lang.OutOfMemory異常并且讓程序可用內存過小。

如下為位圖建立LruCache的例子:

private LruCache<String, Bitmap> mMemoryCache;@Override protected void onCreate(Bundle savedInstanceState) {...// Get max available VM memory, exceeding this amount will throw an// OutOfMemory exception. Stored in kilobytes as LruCache takes an// int in its constructor.final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);// Use 1/8th of the available memory for this memory cache.final int cacheSize = maxMemory / 8;mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) {// The cache size will be measured in kilobytes rather than// number of items.return bitmap.getByteCount() / 1024;}};... }public void addBitmapToMemoryCache(String key, Bitmap bitmap) {if (getBitmapFromMemCache(key) == null) {mMemoryCache.put(key, bitmap);} }public Bitmap getBitmapFromMemCache(String key) {return mMemoryCache.get(key); } 注意:在這個例子中,八分之一應用程序內存分配給了我們的緩存。在一般或高分辨率設備上,至少為4M內存(32/8)。800*480分辨率的設備上的全屏GridView大概會使用1.5MB (800*480*4 bytes),因此會內存中會至少緩存2.5頁圖片。

當將Bitmap加入ImageView的時候,LruCache會先被檢查。如果內存中存在此Bitmap,則會用它更新ImageView,否則使用背景線程來獲取圖片:

public void loadBitmap(int resId, ImageView imageView) {final String imageKey = String.valueOf(resId);final Bitmap bitmap = getBitmapFromMemCache(imageKey);if (bitmap != null) {mImageView.setImageBitmap(bitmap);} else {mImageView.setImageResource(R.drawable.image_placeholder);BitmapWorkerTask task = new BitmapWorkerTask(mImageView);task.execute(resId);} }

BitmapWorkerTask用于獲取Bitmap并將獲取得Bitmap存入LruCache中:

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {...// Decode image in background.@Overrideprotected Bitmap doInBackground(Integer... params) {final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), params[0], 100, 100));addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);return bitmap;}... }

使用磁盤緩存(Use a Disk Cache)

內存緩存可以加速獲取最近瀏覽過的Bitmap,但是你不能完全依賴內存緩存。像GridView這樣攜帶大數據的組件很容易將內存緩存填滿。而且,你的應用程序可能被外來程序打斷如電話,此時背景線程可能被殺死,內存可能被銷毀。一旦用戶回過頭的時候,你的應用又得重新處理每張圖片了。這些情況發生的時候,我們可以使用磁盤緩存來保存已經加載過的圖片,在內存緩存不在的情況下,降低圖片加載時間。當然,從磁盤中提取圖片比從內存中加載圖片要慢一些并且需要為其開啟額外線程用于處理。因為磁盤的讀寫是不可預測的。

注意:如果頻繁的訪問圖片,ContentProvider可能是最好的地方來存儲緩存圖片。例如相冊程序

例子:

private DiskLruCache mDiskLruCache; private final Object mDiskCacheLock = new Object(); private boolean mDiskCacheStarting = true; private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB private static final String DISK_CACHE_SUBDIR = "thumbnails";@Override protected void onCreate(Bundle savedInstanceState) {...// Initialize memory cache...// Initialize disk cache on background threadFile cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);new InitDiskCacheTask().execute(cacheDir);... }class InitDiskCacheTask extends AsyncTask<File, Void, Void> {@Overrideprotected Void doInBackground(File... params) {synchronized (mDiskCacheLock) {File cacheDir = params[0];mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);mDiskCacheStarting = false; // Finished initializationmDiskCacheLock.notifyAll(); // Wake any waiting threads}return null;} }class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {...// Decode image in background.@Overrideprotected Bitmap doInBackground(Integer... params) {final String imageKey = String.valueOf(params[0]);// Check disk cache in background threadBitmap bitmap = getBitmapFromDiskCache(imageKey);if (bitmap == null) { // Not found in disk cache// Process as normalfinal Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), params[0], 100, 100));}// Add final bitmap to cachesaddBitmapToCache(imageKey, bitmap);return bitmap;}... }public void addBitmapToCache(String key, Bitmap bitmap) {// Add to memory cache as beforeif (getBitmapFromMemCache(key) == null) {mMemoryCache.put(key, bitmap);}// Also add to disk cachesynchronized (mDiskCacheLock) {if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {mDiskLruCache.put(key, bitmap);}} }public Bitmap getBitmapFromDiskCache(String key) {synchronized (mDiskCacheLock) {// Wait while disk cache is started from background threadwhile (mDiskCacheStarting) {try {mDiskCacheLock.wait();} catch (InterruptedException e) {}}if (mDiskLruCache != null) {return mDiskLruCache.get(key);}}return null; }// Creates a unique subdirectory of the designated app cache directory. Tries to use external // but if not mounted, falls back on internal storage. public static File getDiskCacheDir(Context context, String uniqueName) {// Check if media is mounted or storage is built-in, if so, try and use external cache dir// otherwise use internal cache dirfinal String cachePath =Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||!isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :context.getCacheDir().getPath();return new File(cachePath + File.separator + uniqueName); } 注意:初始化磁盤緩存需要磁盤操作,因此這些操作不能在主線程中執行。但是這意味著在磁盤緩存初始化之前,可能會訪問緩存。為了處理這個問題,通過鎖對象確保應用程序在磁盤初始化之后,才可以從磁盤緩存中讀取。

雖然內存緩存在UI線程中被檢查,但是磁盤緩存在背景線程中被檢查。磁盤操作永遠不能在主線程中發生。當圖像被處理完全之后,Bitmap被添加到內存緩存與磁盤緩存中。

處理配置發生改變的情況(Handle Configuration Changes)

運行配置發生改變,例如屏幕旋轉改變,會造成Android銷毀Activity并重啟帶有新配置的Activity。如果當配置發生改變的時候,你想要避免再次處理你的圖片以便用戶能夠有一個平滑和快速的體驗效果。你可以使用上述提到的內存緩存機制,借助于中間組件Fragment的方法setRetainInstance(true)來保存內存換,然后實現將其傳遞到新的Activity中。當Activity被重建之后,通過Fragment獲取內存緩存對象,并且從其中提取對象到ImageView中。

如下當應用程序配置發生改變的時候,通過Fragment重新獲得LruCache對象

private LruCache<String, Bitmap> mMemoryCache;@Override protected void onCreate(Bundle savedInstanceState) {...RetainFragment retainFragment =RetainFragment.findOrCreateRetainFragment(getFragmentManager());mMemoryCache = retainFragment.mRetainedCache;if (mMemoryCache == null) {mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {... // Initialize cache here as usual}retainFragment.mRetainedCache = mMemoryCache;}... }class RetainFragment extends Fragment {private static final String TAG = "RetainFragment";public LruCache<String, Bitmap> mRetainedCache;public RetainFragment() {}public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);if (fragment == null) {fragment = new RetainFragment();fm.beginTransaction().add(fragment, TAG).commit();}return fragment;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setRetainInstance(true);} }

總結

以上是生活随笔為你收集整理的Bitmap Cache的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩中文字幕第一页 | 丝袜+亚洲+另类+欧美+变态 | 亚洲成人www | 尤物在线免费观看 | 色人阁在线视频 | 六月久久| 黑人巨大精品欧美 | 91啪国产 | 欧美国产精品一二三 | 在线观看黄色动漫 | 青青射 | 麻豆视频播放 | 欧美精品色婷婷五月综合 | 在线观看一二区 | 欧美在线看片 | 最色成人网 | 精品国产一区二区三区无码 | 中文字幕免费高清在线观看 | 亚洲欧美日韩国产综合 | 成人av免费在线看 | 国产盗摄av| 午夜私人福利 | 亚洲成人乱码 | 日本亲与子乱xxx | 日韩三级麻豆 | 亚洲av无码国产精品久久不卡 | 亚洲人成在线观看 | 日本免费在线一区 | 一本色道久久综合亚洲精品酒店 | 伊人中文在线 | 国产精品xxxx喷水欧美 | 欧美成人精品在线 | 一区二区日本 | 国产视频综合在线 | 羞辱狗奴的句子有哪些 | 久久久亚洲av波多野结衣 | 成人激情视频在线观看 | 日本亚洲一区二区三区 | 国产又大又黄又粗 | 成人导航网站 | 中文字幕视频观看 | 日韩欧美高清在线视频 | 好吊一区二区三区视频 | av福利站| 午夜福利毛片 | 伊人天堂网 | 亚洲第一综合 | 亚洲综合站 | 国产综合内射日韩久 | 免费成人结看片 | 男女免费观看视频 | 男人天堂avav | 中文字幕在线看人 | 婷婷五月色综合 | 91精品国产高清91久久久久久 | 欧美成人一区二区三区 | 欧美精品乱人伦久久久久久 | 久久国产日韩 | 国产精品剧情一区 | 日本视频精品 | 日韩中文久久 | 一级大片网站 | 影音先锋在线播放 | 国产精品一区二区黑人巨大 | 亚洲免费视频播放 | 午夜国产福利 | 久久午夜电影 | 日韩视频成人 | 日本中文字幕有码 | 操操操影院 | 免费黄色看片网站 | 先锋影音av资源在线 | 欧美激情电影一区二区 | 国产精品天美传媒入口 | 天天综合天天添夜夜添狠狠添 | 丝袜操| 日韩在线色 | 一级黄色a级片 | 97在线精品视频 | 久久国产精品区 | 天堂精品久久 | 日本人妻换人妻毛片 | 日日噜噜噜| 少妇爽| 91香蕉在线视频 | 国产一区二区三区色淫影院 | 国产一级在线免费观看 | 午夜久久久久久久久久久 | 很黄的网站在线观看 | 五月天色婷婷综合 | 欧美偷拍第一页 | 精品久久ai | 视频精品一区二区 | 日本少妇吞精囗交 | 夜夜操夜夜干 | 奇米色777 | 国产私拍视频 | 欧美经典一区二区三区 | 精品视频一二三区 |