Android Open Source - SIC L R U Cache






From Project

Back to project page SIC.

License

The source code is released under:

MIT License

If you think the Android project SIC listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.sun.imageloader.cache.impl;
/*from  w ww.  j a v a  2  s .  c  o  m*/
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;

import android.graphics.Bitmap;
import android.media.Image;
import android.util.Log;

import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.EntryWeigher;
import com.googlecode.concurrentlinkedhashmap.EvictionListener;
import com.sun.imageloader.core.ImageKey;
import com.sun.imageloader.utils.L;

public class LRUCache extends SoftCache<ImageKey, Bitmap> implements EntryWeigher<ImageKey, Bitmap>,  EvictionListener<ImageKey, Bitmap>{

  private final ConcurrentMap<ImageKey, Bitmap> _lruHardCache;
  private int _currentSizeMemory;
  private static final String TAG = LRUCache.class.getName();
  private AtomicBoolean _isAlreadyTrimmingCache = new AtomicBoolean();
  private static final int INITAIL_CAP = 20;
  
  /**
   * This implementation keeps a reference to {@link Bitmap} objects keyed to it's {@link ImageKey}. Once the internal cache size
   * reaches an internal limit specified in MB through the constructor, an item is evicted. This is then promoted to the 
   * softcache which maintains a {@link SoftReference} to the {@link Bitmap} object, which can be removed by when a GC happens.
   * 
   * This implementation is thread safe
   * 
   * @param maxSizeMemory_ 
   *       measured in MB
   */
  public LRUCache(int maxSizeMemory_) {
    super(maxSizeMemory_);
    Log.v(TAG, "max mem size " + getMaxCacheSizeInMB());
    // this is where the magic happens
    _lruHardCache = new ConcurrentLinkedHashMap.Builder<ImageKey, Bitmap>()
          .maximumWeightedCapacity((getMaxCacheSizeInMB()))
        .initialCapacity(INITAIL_CAP)
        .weigher(this)
        .listener(this)
        .build();
  }


  @Override
  protected float sizeOfValue(Bitmap value_) {
    float memory =  (value_.getRowBytes() * value_.getHeight()) ;
    L.v(TAG, "Memory size if image: " + memory) ;
    return memory;
  }

  /**
   * @param key_ {@link ImageKey} which is used to uniquely identify a {@link Bitmap} image
   * @param value_ the {@link Bitmap} image
   * 
   * @return true if the previous value is not null
   */
  @Override
  public boolean put(ImageKey key_, Bitmap value_) {

    if (key_ == null || value_ == null) {
      throw new NullPointerException("key or value supplied was null");
    }

    Bitmap previousBitmap;
    previousBitmap = _lruHardCache.put(key_, value_);
        
    if(previousBitmap != null){
      return true;
    }else{
      return false;
    }

//    synchronized (_putLock) {
//      _currentSizeMemory += sizeOfValue(value_);
//      if (previousBitmap != null) {
//        _currentSizeMemory -= sizeOfValue(value_);
//      }
//    }

  }

  
  /**
   * 
   * This method is now deprecated, but is still here for reference purposes.
   * 
   * Trim the cache size
   *  
   * @param maxMemorySize_
   * 
   */
  @Deprecated
  protected void trimeCache(int maxMemorySize_) {
    _isAlreadyTrimmingCache.getAndSet(true);
    L.v(TAG, "Inside trime method, current max memopry size is in bytes: " + maxMemorySize_ + " cache size: " +_lruHardCache.size() );
    while(_currentSizeMemory >= maxMemorySize_){
      
      if (_currentSizeMemory < 0 || (_lruHardCache.isEmpty() && _currentSizeMemory != 0)) {
        throw new IllegalStateException(this.getClass().getName() + "Inconsistent memory size for cache when compared to cache size or memory size of map is below 0");
      }
        Map.Entry<ImageKey, Bitmap> entry = _lruHardCache.entrySet().iterator().next();
        Bitmap bitMapToRemove = entry.getValue();
        ImageKey bitMapToRemoveKey = entry.getKey();
        
        if(bitMapToRemove == null){
          break;
        }
        _currentSizeMemory -= sizeOfValue(bitMapToRemove);
        // lets add  image to the softcache so that we can retrieve it from the soft cache if there is a
        // cache miss in the hard cache. That is if any GC hasn't discarded it already
        // in that case we have no choice but to go ahead and retreive it again from url/disc.
        L.v(TAG, "Removing image with key: " + bitMapToRemoveKey.key());
        super.put(bitMapToRemoveKey, bitMapToRemove);
        _lruHardCache.remove(bitMapToRemoveKey);    
    }
    _isAlreadyTrimmingCache.getAndSet(false);
  }

  @Override
  protected Reference<Bitmap> creatObjectReference(Bitmap value_) {
    Reference<Bitmap> softReferenceBitMap = new SoftReference<Bitmap>(value_);
    return softReferenceBitMap;
  }

  /**
   * Retrieve the {@link Bitmap} object from the internal cache
   * 
   * @param key_ the {@link Image} used to retrieve the {@link Bitmap} in the cache
   * @return the {@link Bitmap} image
   */
  @Override
  public Bitmap getValue(ImageKey key_) {
    Bitmap bitMap;
    bitMap = _lruHardCache.get(key_);

    if (bitMap != null) {
      return bitMap;
    }
    
    bitMap = super.getValue(key_);
    
    //If we find that the image exists in the softcache, then we can simply promote that to the hardCache
    if (bitMap != null) {
        put(key_, bitMap);
      return bitMap;
    }else{
      //Well where because we found nothing for the key specified, which means GC banished the bitmap to Object hell
      //TODO think about raising an exception rather than return null
      return null;
    }

  }
  
  @Override
  public void remove(ImageKey key_, boolean removeAllOccurences_){
    remove(key_);
    
    if(removeAllOccurences_)
      super.remove(key_);
  }

  
  protected void remove(String key_) {
    _lruHardCache.remove(key_);
  }

  @Override
  public Collection<ImageKey> getKeys() {
    return super.getKeys();
  }



  @Override 
  public int weightOf(ImageKey key, Bitmap value) {
        float bytes = sizeOfValue(value);
        return (int) bytes;
  }

  @Override
  public void onEviction(ImageKey key_, Bitmap value_) {
    L.v(TAG, "Evicted ImageKey=" + key_ + ", with bitmap size=" + sizeOfValue(value_));
    super.put(key_, value_);
  }
  
  
  

}




Java Source Code List

com.sun.imageloader.cache.api.MemoryCache.java
com.sun.imageloader.cache.impl.DiskCache.java
com.sun.imageloader.cache.impl.ImageFileFilter.java
com.sun.imageloader.cache.impl.LRUCache.java
com.sun.imageloader.cache.impl.SoftCache.java
com.sun.imageloader.computable.impl.ComputableImage.java
com.sun.imageloader.computable.impl.Computable.java
com.sun.imageloader.concurrent.ComputableCallable.java
com.sun.imageloader.concurrent.DisplayImageTask.java
com.sun.imageloader.concurrent.ImageLoaderTask.java
com.sun.imageloader.core.FlingLock.java
com.sun.imageloader.core.ImageKey.java
com.sun.imageloader.core.ImagePreferences.java
com.sun.imageloader.core.ImageSettings.java
com.sun.imageloader.core.ImageWriter.java
com.sun.imageloader.core.SimpleImageListenerImpl.java
com.sun.imageloader.core.UrlImageLoaderConfiguration.java
com.sun.imageloader.core.UrlImageLoader.java
com.sun.imageloader.core.UrlImageTaskExecutor.java
com.sun.imageloader.core.api.FailedTaskReason.java
com.sun.imageloader.core.api.ImageFailListenter.java
com.sun.imageloader.core.api.ImageTaskListener.java
com.sun.imageloader.core.api.Settings.java
com.sun.imageloader.downloader.api.ImageRetriever.java
com.sun.imageloader.downloader.impl.ImageDownloader.java
com.sun.imageloader.downloader.impl.ImageRetrieverFactory.java
com.sun.imageloader.downloader.impl.Scheme.java
com.sun.imageloader.imagedecoder.api.ImageDecoder.java
com.sun.imageloader.imagedecoder.impl.SimpleImageDecoder.java
com.sun.imageloader.memorizer.api.AMemorizer.java
com.sun.imageloader.memorizer.api.BitmapMemorizer.java
com.sun.imageloader.memorizer.api.IMemorizer.java
com.sun.imageloader.memorizer.api.InterruptedImageLoadException.java
com.sun.imageloader.utils.KeyUtils.java
com.sun.imageloader.utils.L.java
com.sun.imageloader.utils.ViewUtils.java