/******************************************************************************* * Copyright 2011, 2012, 2013 fanfou.com, Xiaoke, Zhang * * 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. *******************************************************************************/ package com.fanfou.app.opensource.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.lang.ref.SoftReference; import java.util.concurrent.ConcurrentHashMap; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; import com.fanfou.app.opensource.AppContext; import com.fanfou.app.opensource.util.IOHelper; import com.fanfou.app.opensource.util.ImageHelper; import com.fanfou.app.opensource.util.StringHelper; /** * @author mcxiaoke * @version 1.0 2011.06.01 * @version 1.1 2011.09.23 * @version 1.5 2011.11.23 * @version 1.6 2011.11.24 * @version 1.7 2011.12.05 * @version 1.8 2011.12.09 * */ final class ImageCache implements ICache<Bitmap> { private static final String TAG = ImageCache.class.getSimpleName(); public static final int IMAGE_QUALITY = 100; public static ImageCache INSTANCE = null; public synchronized static ImageCache getInstance() { if (ImageCache.INSTANCE == null) { ImageCache.INSTANCE = new ImageCache(AppContext.getAppContext()); } return ImageCache.INSTANCE; } final ConcurrentHashMap<String, SoftReference<Bitmap>> memoryCache; private File mCacheDir = null; Context mContext; private ImageCache(final Context context) { this.mContext = context; this.memoryCache = new ConcurrentHashMap<String, SoftReference<Bitmap>>(); this.mCacheDir = IOHelper.getImageCacheDir(this.mContext); } @Override public void clear() { final String[] files = this.mContext.fileList(); for (final String file : files) { this.mContext.deleteFile(file); } synchronized (this) { this.memoryCache.clear(); } } @Override public boolean containsKey(final String key) { return get(key) != null; } @Override public Bitmap get(final String key) { if (StringHelper.isEmpty(key)) { return null; } Bitmap bitmap = null; final SoftReference<Bitmap> reference = this.memoryCache.get(key); if (reference != null) { bitmap = reference.get(); } if (bitmap == null) { bitmap = loadFromFile(key); if (bitmap == null) { this.memoryCache.remove(key); } else { if (AppContext.DEBUG) { Log.d(ImageCache.TAG, "get() bitmap from disk, put to memory cache"); } this.memoryCache.put(key, new SoftReference<Bitmap>(bitmap)); } } return bitmap; } @Override public int getCount() { return this.memoryCache.size(); } @Override public boolean isEmpty() { return this.memoryCache.isEmpty(); } private Bitmap loadFromFile(final String key) { final String filename = StringHelper.md5(key) + ".jpg"; final File file = new File(this.mCacheDir, filename); FileInputStream fis = null; Bitmap bitmap = null; try { fis = new FileInputStream(file); bitmap = BitmapFactory.decodeStream(fis); if (AppContext.DEBUG) { Log.d(ImageCache.TAG, "loadFromFile() key is " + key); } } catch (final FileNotFoundException e) { if (AppContext.DEBUG) { Log.d(ImageCache.TAG, "loadFromFile: " + e.getMessage()); } } finally { IOHelper.forceClose(fis); } return bitmap; } @Override public boolean put(final String key, final Bitmap bitmap) { if ((key == null) || (bitmap == null)) { return false; } this.memoryCache.put(key, new SoftReference<Bitmap>(bitmap)); final boolean result = writeToFile(key, bitmap); if (AppContext.DEBUG) { Log.d(ImageCache.TAG, "put() put to cache, write to disk result=" + result); } return result; } protected boolean replace(final String oldKey, final String key, final Bitmap bitmap) { boolean result = false; put(key, bitmap); synchronized (this) { result = this.memoryCache.put(key, new SoftReference<Bitmap>(bitmap)) != null; this.memoryCache.remove(oldKey); } this.mContext.deleteFile(StringHelper.md5(oldKey)); return result; } private boolean writeToFile(final String key, final Bitmap bitmap) { final String filename = StringHelper.md5(key) + ".jpg"; return ImageHelper.writeToFile(new File(this.mCacheDir, filename), bitmap); } }