com.crossbow.volley.toolbox.CrossbowImageCache.java Source code

Java tutorial

Introduction

Here is the source code for com.crossbow.volley.toolbox.CrossbowImageCache.java

Source

package com.crossbow.volley.toolbox;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.support.v4.graphics.BitmapCompat;
import android.support.v4.util.LruCache;

import com.android.volley.VolleyLog;
import com.android.volley.toolbox.ImageLoader;

import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * Copyright (C) 2014 Patrick Doyle
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Image cache used for the Image loader. This will also get the least recently used
 * bitmap and try use that to decode new bitmaps in the image request.
 */
public class CrossbowImageCache implements ImageLoader.ImageCache {

    private static final int UNUSED_BITMAP_COUNT = 50;
    private LruCache<String, Bitmap> imageCache;
    private Set<WeakReference<Bitmap>> unusedBitmaps = Collections
            .newSetFromMap(new LinkedHashMap<WeakReference<Bitmap>, Boolean>(UNUSED_BITMAP_COUNT) {
                protected boolean removeEldestEntry(Map.Entry<WeakReference<Bitmap>, Boolean> eldest) {
                    boolean shouldRemove = size() > UNUSED_BITMAP_COUNT;
                    if (shouldRemove) {
                        VolleyLog.d("pruning unused size = " + size());
                    }
                    return shouldRemove;
                }
            });

    /**
     * @param size - number of byes to use for the cache;
     */
    protected CrossbowImageCache(int size) {
        imageCache = new LruCache<String, Bitmap>(size) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    return value.getAllocationByteCount();
                } else {
                    return value.getRowBytes() * value.getHeight();
                }
            }
        };
    }

    @Override
    public synchronized Bitmap getBitmap(String url) {
        return imageCache.get(url);
    }

    @Override
    public synchronized void putBitmap(String url, Bitmap bitmap) {
        imageCache.put(url, bitmap);
    }

    public Bitmap getBitmapToFill(BitmapFactory.Options options) {
        synchronized (imageCache) {
            for (WeakReference<Bitmap> bitmapSoftReference : unusedBitmaps) {
                if (bitmapSoftReference.get() != null) {
                    Bitmap bitmap = bitmapSoftReference.get();
                    if (bitmap.isMutable() && canUseForInBitmap(bitmap, options)) {
                        unusedBitmaps.remove(bitmapSoftReference);
                        return bitmap;
                    }
                }
            }
        }

        return null;
    }

    public void storeForReUse(Bitmap bitmap) {
        synchronized (imageCache) {
            if (bitmapCanBeReused(bitmap)) {
                unusedBitmaps.add(new WeakReference<Bitmap>(bitmap));
            }
        }
    }

    private static boolean bitmapCanBeReused(Bitmap bitmap) {
        return bitmap != null && !bitmap.isRecycled() && bitmap.isMutable();
    }

    private static boolean canUseForInBitmap(Bitmap candidate, BitmapFactory.Options targetOptions) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

            if (targetOptions.inSampleSize == 0) {
                final int width = targetOptions.outWidth;
                final int height = targetOptions.outHeight;
                final int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
                return byteCount <= BitmapCompat.getAllocationByteCount(candidate);
            }
            final int width = targetOptions.outWidth / targetOptions.inSampleSize;
            final int height = targetOptions.outHeight / targetOptions.inSampleSize;
            final int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
            return byteCount <= BitmapCompat.getAllocationByteCount(candidate);
        }

        return candidate.getWidth() == targetOptions.outWidth && candidate.getHeight() == targetOptions.outHeight
                && targetOptions.inSampleSize == 1;
    }

    private static int getBytesPerPixel(Bitmap.Config config) {
        if (config == Bitmap.Config.ARGB_8888) {
            return 4;
        } else if (config == Bitmap.Config.RGB_565) {
            return 2;
        } else if (config == Bitmap.Config.ARGB_4444) {
            return 2;
        } else if (config == Bitmap.Config.ALPHA_8) {
            return 1;
        }
        return 1;
    }
}