private void DisplayFinished ( AndroidCachingBitmapDrawable cachedDrawable ) { _cacheLock.EnterWriteLock(); try { if (_displayedCache.ContainsKey(cachedDrawable.CacheKey)) { // demote displayed entry to reuse pool cachedDrawable.DisplayStarted = null; cachedDrawable.DisplayFinished = DisplayStarted; _displayedCache.Remove(cachedDrawable.CacheKey); _reusePool.Add(cachedDrawable.CacheKey, cachedDrawable); } } finally { _cacheLock.ExitWriteLock(); } }
private void ProcessRemoval ( AndroidCachingBitmapDrawable bitmapDrawable, bool isEvicted ) { if (_cacheLock.IsWriteLockHeld == false) { throw new SynchronizationLockException(nameof(_cacheLock)); } // We only really care about evictions because we do direct Remove()als // all the time when promoting to the displayed cache. Only when the // entry has been evicted is it truly not longer being held by us. if (isEvicted) { UpdateByteUsage(bitmapDrawable.Bitmap, //decrement: true, eviction: true); bitmapDrawable.DisplayStarted = null; bitmapDrawable.DisplayFinished = null; bitmapDrawable.IsCached = false; } }
public void AddBitmapDrawableToCache ( string bitmapKey, AndroidCachingBitmapDrawable bitmapDrawable ) { if ((bitmapDrawable == null) || (bitmapDrawable.Bitmap == null)) { throw new ArgumentException("Attempt to add null value, refusing to cache.", nameof(bitmapDrawable)); } _cacheLock.EnterWriteLock(); try { if ((_displayedCache.ContainsKey(bitmapKey) == false) && (_reusePool.ContainsKey(bitmapKey) == false)) { _reusePool.Add(bitmapKey, bitmapDrawable); bitmapDrawable.IsCached = true; bitmapDrawable.CacheKey = bitmapKey; bitmapDrawable.DisplayStarted = DisplayStarted; UpdateByteUsage(bitmapDrawable.Bitmap, //decrement : false, eviction: false); } } finally { _cacheLock.ExitWriteLock(); } }
public AndroidCachingBitmapDrawable GetReusableBitmapDrawable ( int bitmapWidth, int bitmapHeight ) { // Only attempt to get a bitmap for reuse if the reuse cache is full. // This prevents us from prematurely depleting the pool and allows // more cache hits, as the most recently added entries will have a high // likelihood of being accessed again so we don't want to steal those bytes // too soon. _cacheLock.EnterWriteLock(); // because of _refillNeeded try { if (_reusePool.CacheSizeInBytes < _lowWatermark && _refillNeeded) { // Reuse pool is not full, refusing reuse request: //total_reuse_misses++; return(null); } _refillNeeded = false; AndroidCachingBitmapDrawable reuseDrawable = null; if (_reusePool.Count > 0) { foreach (string poolKey in _reusePool.Keys) { AndroidCachingBitmapDrawable poolDrawable = GetBitmapDrawableFromPool(poolKey, updateLru: false); // TODO: Implement check for KitKat and higher since // bitmaps that are smaller than the requested size can be used. if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat) { // We can reuse a bitmap if the allocation to be reused is larger // than the requested bitmap: if ((poolDrawable.Bitmap.Width >= bitmapWidth) && (poolDrawable.Bitmap.Height >= bitmapHeight) && (poolDrawable.IsRetained == false)) { reuseDrawable = poolDrawable; break; // reuse hit, using larger allocation. } } else if ((poolDrawable.Bitmap.Width == bitmapWidth) && (poolDrawable.Bitmap.Height == bitmapHeight) && (poolDrawable.Bitmap.IsMutable) && (poolDrawable.IsRetained == false)) { reuseDrawable = poolDrawable; break; // reuse hit } } if (reuseDrawable != null) { reuseDrawable.IsRetained = true; UpdateByteUsage(reuseDrawable.Bitmap, //decrement : true, eviction: true); // Cleanup the entry reuseDrawable.DisplayStarted = null; reuseDrawable.DisplayFinished = null; reuseDrawable.IsCached = false; _reusePool.Remove(reuseDrawable.CacheKey); //total_reuse_hits++; } } if (reuseDrawable == null) { //total_reuse_misses++; // Indicate that the pool may need to be refilled. // There is little harm in setting this flag since it will be unset // on the next reuse request if the threshold is // _reusePool.CacheSizeInBytes >= _lowWatermark. _refillNeeded = true; } return(reuseDrawable); } finally { _cacheLock.ExitWriteLock(); } }