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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android的图片缓存ImageCache(转)

發布時間:2024/4/17 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android的图片缓存ImageCache(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么要做緩存???????

??????? 在UI界面加載一張圖片時很簡單,然而如果需要加載多張較大的圖像,事情就會變得更加復雜。在許多情況下(如ListView、GridView或ViewPager等的組件),屏幕上的圖片的總數伴隨屏幕的滾動會大大增加,且基本上是無限的。

為了使內存使用保持在穩定范圍內,防止出現OOM,這些組件會在子view畫出屏幕后,對其進行資源回收,并重新顯示新出現的圖片,垃圾回收機制會釋放掉不再顯示的圖片的內存空間。但是這樣頻繁地處理圖片的加載和回收不利于操作的流暢性,而內存或者磁盤的Cache就會幫助解決這個問題,實現快速加載已加載的圖片。 在緩存上,主要有兩種級別的Cache:LruCache和DiskLruCache。?前者是基于內存的,后者是基于磁盤的。

如何在內存中做緩存?

?????? 通過內存緩存可以快速加載緩存圖片,但會消耗應用的內存空間。LruCache類(通過兼容包可以支持到sdk4)很適合做圖片緩存,它通過LinkedHashMap保持圖片的強引用方式存儲圖片,當緩存空間超過設置定的限值時會釋放掉早期的緩存。

??注:在過去,常用的內存緩存實現是通過SoftReference或WeakReference,但不建議這樣做。從Android2.3(API等級9)垃圾收集器開始更積極收集軟/弱引用,這使得它們相當無效。此外,在Android 3.0(API等級11)之前,存儲在native內存中的可見的bitmap不會被釋放,可能會導致應用程序暫時地超過其內存限制并崩潰。

?

為了給LruCache設置合適的大小,需要考慮以下幾點因素:

  • 你的應用中空閑內存是多大?

  • 你要在屏幕中一次顯示多少圖片? 你準備多少張圖片用于顯示?

  • 設備的屏幕大小與density 是多少?超高屏幕density的設備(xhdpi)像Galaxy Nexus 比 Nexus S (hdpi)這樣的設備在緩存相同的圖片時需要更大的Cache空間。

  • 圖片的大小和屬性及其需要占用多少內存空間?

  • 圖片的訪問頻率是多少? 是否比其他的圖片使用的頻率高?如果這樣你可能需要考慮將圖片長期存放在內存中或者針對不同類型的圖片使用不同的緩存策略。

  • 如何平衡質量與數量,有事你可能會存儲一些常用的低質量的圖片用戶顯示,然后通過異步線程加載高質量的圖片。

圖片緩存方案沒有固定的模式使用所有的的應用,你需要根據應用的具體應用場景進行分析,選擇合適的方案來做,緩存太小不能發揮緩存的優勢,太大可能占用過多的內存,降低應用性能,或者發生內存溢出異常,

下面是一個使用LruCache的例子:

private LruCache mMemoryCache; @Override protected void onCreate(Bundle savedInstanceState) { ... // Get memory class of this device, exceeding this amount will throw an OutOfMemory exception. final int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass(); // Use 1/8th of the available memory for this memory cache. final int cacheSize = 1024 * 1024 * memClass / 8; mMemoryCache = new LruCache(cacheSize) { @Overrideprotected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in bytes rather than number of items. return bitmap.getByteCount(); } }; ... } public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); } } public Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key); }

??注意:在這個例子中,應用八分之一的內存分配給圖片緩存,在普通/hdpi設備中大約為4MB(32/8)。GirdView全屏時在800x480分辨率的設備中需要1.5M圖片空間(800*480*4 bytes),這樣就可以在內存中緩存2.5屏的圖片。

?

運用LruCache向ImageView添加圖片時首先先檢查圖片是否存在,如果在直接更行ImageView,否則通過后臺線程加載圖片:

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

?

BitmapWorkerTask需要將將加載的圖片添加到緩存中:

class BitmapWorkerTask extends AsyncTask { ... // 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; } ... }

?

如何使用磁盤緩存?

內存緩存對訪問最近使用的圖片時很高效,但是你不能保證它一直會在緩存中。像GirdView這樣大數據量的組件很容易充滿內存緩存。你的應用可能會被“來電”打斷,在后臺時可能會被殺掉,內存緩存就會失效,一旦用戶重新回到應用中時,你需要重新處理每個圖片。

在這種情況下我們可以運用磁盤緩存存儲已處理的圖片,當圖片不再內存中時,減少重新加載的時間,當然從磁盤加載圖片時要比內存中慢,需要在后臺線程中做,因為磁盤的讀取時間是未知的。

注意:如果你經常訪問圖片,ContentProvider應該是存儲圖片的好地方,如:Gallery圖片管理應用。

下面是一個簡單的DiskLruCache實現。然而推薦的實現DiskLruCache方案請參考Android4.0中(libcore/luni/src/main/java/libcore/io/DiskLruCache.java)源碼。本文使用的是之前版本中的簡單實現(Quick Search中是另外的實現).

顯示是簡單實現DiskLruCache更新后的例子:

private DiskLruCache mDiskCache; 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 ... File cacheDir = getCacheDir(this, DISK_CACHE_SUBDIR); mDiskCache = DiskLruCache.openCache(this, cacheDir, DISK_CACHE_SIZE); ... } class BitmapWorkerTask extends AsyncTask { ... // Decode image in background. @Overrideprotected Bitmap doInBackground(Integer... params) { final String imageKey = String.valueOf(params[0]); // Check disk cache in background thread Bitmap bitmap = getBitmapFromDiskCache(imageKey); if (bitmap == null) { // Not found in disk cache // Process as normal final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), params[0], 100, 100)); } // Add final bitmap to caches addBitmapToCache(String.valueOf(imageKey, bitmap); return bitmap; } ... } public void addBitmapToCache(String key, Bitmap bitmap) { // Add to memory cache as before if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); } // Also add to disk cache if (!mDiskCache.containsKey(key)) { mDiskCache.put(key, bitmap); } } public Bitmap getBitmapFromDiskCache(String key) { return mDiskCache.get(key); } // 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 getCacheDir(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 dir final String cachePath = (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED || !Environment.isExternalStorageRemovable()) ? context.getExternalCacheDir().getPath() : context.getCacheDir().getPath(); return new File(cachePath + File.separator + uniqueName); }

內存緩存檢查在UI線程中做,磁盤緩存的檢查在后臺線程中。硬盤操作不應在UI線程中。圖片處理完成后應將其加入正在使用的內存、磁盤緩存中。

如何處理配置的改變?

應用運行中配置改變時,如屏幕方向改變時為了應用新的配置Android會銷毀重新運行當前的Activity,此時,為了給用戶快速、平緩的用戶體驗你可能不想重新加載圖片。

多虧你運行了緩存技術,緩存可以通過 setRetainInstance(true))傳遞給新的Activity,在Activity重啟后,你可以通過附著的Fragment重新使用已存在的緩存,這樣就可以快速加載到ImageView中了。

下面是一個當配置改變時用Fragment重用已有的緩存的例子:

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

為了測試,在使用和未使用Fragment的情況下,強制旋轉屏幕,你會發現從保留內存緩存加載圖片時幾乎沒有滯后。

?

轉自:鏈接

轉載于:https://www.cnblogs.com/YangBinChina/p/4618415.html

總結

以上是生活随笔為你收集整理的Android的图片缓存ImageCache(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

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