From 4985945dcba88dbd618cdb0f9a5c3e01ae8342c7 Mon Sep 17 00:00:00 2001 From: seven332 Date: Mon, 30 Mar 2015 17:57:22 +0800 Subject: [PATCH] Update cache --- .../java/com/hippo/ehviewer/AppContext.java | 2 +- .../com/hippo/ehviewer/cache/AnyCache.java | 263 ++++++++++++++---- .../com/hippo/ehviewer/cache/ImageCache.java | 30 +- .../com/hippo/ehviewer/ui/AbsActivity.java | 8 + 4 files changed, 228 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/AppContext.java b/app/src/main/java/com/hippo/ehviewer/AppContext.java index f15a3912b..c26836d9c 100644 --- a/app/src/main/java/com/hippo/ehviewer/AppContext.java +++ b/app/src/main/java/com/hippo/ehviewer/AppContext.java @@ -148,7 +148,7 @@ public class AppContext extends Application implements UncaughtExceptionHandler */ @Override public void onLowMemory() { - ImageCache.getImageCache(this).evictAll(); + ImageCache.getImageCache(this).clearMemory(); super.onLowMemory(); } diff --git a/app/src/main/java/com/hippo/ehviewer/cache/AnyCache.java b/app/src/main/java/com/hippo/ehviewer/cache/AnyCache.java index daf208267..12e964216 100644 --- a/app/src/main/java/com/hippo/ehviewer/cache/AnyCache.java +++ b/app/src/main/java/com/hippo/ehviewer/cache/AnyCache.java @@ -35,40 +35,70 @@ public abstract class AnyCache { private static final String TAG = AnyCache.class.getSimpleName(); - private @Nullable LruCache mMemoryCache; + private LruCache mMemoryCache; private @Nullable DiskCache mDiskCache; + private final boolean mHasMemoryCache; + private final boolean mHasDiskCache; + /** * Used to temporarily pause the disk cache while scrolling */ public boolean mPauseDiskAccess = false; private final Object mPauseLock = new Object(); + private final Object mDiskCacheLock = new Object(); + private boolean mDiskCacheStarting = true; + + + public AnyCache(AnyCacheParams params) { + params.isValid(); + mHasMemoryCache = params.hasMemoryCache; + mHasDiskCache = params.hasDiskCache; + + if (mHasMemoryCache) { + initMemoryCache(params.memoryCacheMaxSize); + } + + if (mHasDiskCache) { + initDiskCache(params.diskCacheDir, params.diskCacheMaxSize); + } + } + + + private void initMemoryCache(int maxSize) { + mMemoryCache = new MemoryCahce<>(maxSize, this); + } + + private void initDiskCache(File cacheDir, int maxSize) { + // Set up disk cache + synchronized (mDiskCacheLock) { + try { + mDiskCache = new DiskCache<>(cacheDir, maxSize, this); + } catch (IOException e) { + Log.e(TAG, "Can't create disk cache", e); + } + + // Set up disk cache finished + mDiskCacheStarting = false; + mDiskCacheLock.notifyAll(); + } + } + + protected abstract int sizeOf(String key, V value); protected abstract V read(InputStream is); protected abstract boolean write(OutputStream os, V value); - public void setMemoryCache(int maxSize) { - mMemoryCache = new MemoryCahce(maxSize, this); - } - - public void setDiskCache(File cacheDir, int maxSize) { - try { - mDiskCache = new DiskCache(cacheDir, maxSize, this); - } catch (IOException e) { - Log.w(TAG, "Can't create disk cache", e); - } - } - /** * Check if have memory cache * * @return true if have memory cache */ public boolean hasMemoryCache() { - return mMemoryCache != null; + return mHasMemoryCache; } /** @@ -77,7 +107,7 @@ public abstract class AnyCache { * @return true if have disk cache */ public boolean hasDiskCache() { - return mDiskCache != null; + return mHasDiskCache; } /** @@ -87,7 +117,7 @@ public abstract class AnyCache { * @return the value you get, null for miss or no memory cache */ public V getFromMemory(String key) { - if (mMemoryCache != null) { + if (mHasMemoryCache) { return mMemoryCache.get(key); } else { return null; @@ -101,12 +131,26 @@ public abstract class AnyCache { * @return the value you get, null for miss or no memory cache or get error */ public V getFromDisk(String key) { - if (mDiskCache != null) { + if (mHasDiskCache) { // Wait for pause waitUntilUnpaused(); String diskKey = hashKeyForDisk(key); - return mDiskCache.get(diskKey); + + synchronized (mDiskCacheLock) { + while (mDiskCacheStarting) { + try { + mDiskCacheLock.wait(); + } catch (InterruptedException e) { + // Just ignore + } + } + if (mDiskCache != null) { + return mDiskCache.get(diskKey); + } else { + return null; + } + } } else { return null; } @@ -120,28 +164,22 @@ public abstract class AnyCache { * @return the value you get */ public V get(String key) { - V value; - if (mMemoryCache != null) { - value = mMemoryCache.get(key); - if (value != null) { - return value; - } - } + V value = getFromMemory(key); - if (mDiskCache != null) { - // Wait for pause - waitUntilUnpaused(); - - String diskKey = hashKeyForDisk(key); - value = mDiskCache.get(diskKey); - // Put value to memory cach - if (value != null && mMemoryCache != null) { - mMemoryCache.put(key, value); - } + if (value != null) { + // Get it in memory cache return value; - } else { - return null; } + + value = getFromDisk(key); + + if (value != null) { + // Get it in disk cache + putToMemory(key, value); + return value; + } + + return null; } /** @@ -152,7 +190,7 @@ public abstract class AnyCache { * @return false if no memory cache */ public boolean putToMemory(String key, V value) { - if (mMemoryCache != null) { + if (mHasMemoryCache) { mMemoryCache.put(key, value); return true; } else { @@ -168,12 +206,27 @@ public abstract class AnyCache { * @return false if no disk cache or get error */ public boolean putToDisk(String key, V value) { - if (mDiskCache != null) { + if (mHasDiskCache) { // Wait for pause waitUntilUnpaused(); String diskKey = hashKeyForDisk(key); - return mDiskCache.put(diskKey, value); + + synchronized (mDiskCacheLock) { + while (mDiskCacheStarting) { + try { + mDiskCacheLock.wait(); + } catch (InterruptedException e) { + // Just ignore + } + } + if (mDiskCache != null) { + mDiskCache.put(key, value); + return true; + } else { + return false; + } + } } else { return false; } @@ -186,17 +239,8 @@ public abstract class AnyCache { * @param value the value */ public void put(String key, V value) { - if (mMemoryCache != null) { - mMemoryCache.put(key, value); - } - - if (mDiskCache != null) { - // Wait for pause - waitUntilUnpaused(); - - String diskKey = hashKeyForDisk(key); - mDiskCache.put(diskKey, value); - } + putToMemory(key, value); + putToDisk(key, value); } /** @@ -230,15 +274,54 @@ public abstract class AnyCache { } } + /** + * Evicts all of the items from the memory cache + */ + public void clearMemory() { + if (mHasMemoryCache) { + mMemoryCache.evictAll(); + } + } + + /** + * Clear disk cache + */ + public void clearDisk() { + synchronized (mDiskCacheLock) { + mDiskCacheStarting = true; + if (mDiskCache != null && !mDiskCache.isClosed()) { + try { + mDiskCache.delete(); + } catch (IOException e) { + Log.e(TAG, "AnyCache clearCache", e); + } + File cacheDir = mDiskCache.getCacheDir(); + int maxSize = mDiskCache.getMaxSize(); + mDiskCache = null; + initDiskCache(cacheDir, maxSize); + } + } + } + + public void flush() { + synchronized (mDiskCacheLock) { + if (mDiskCache != null) { + try { + mDiskCache.flush(); + } catch (IOException e) { + Log.e(TAG, "AnyCache flush", e); + } + } + } + } + /** * Evicts all of the items from the memory cache and lets the system know * now would be a good time to garbage collect */ - public void evictAll() { - if (mMemoryCache != null) { - mMemoryCache.evictAll(); - } - System.gc(); + public void clear() { + clearMemory(); + clearDisk(); } /** @@ -278,6 +361,43 @@ public abstract class AnyCache { return builder.toString(); } + /** + * A holder class that contains cache parameters. + */ + public static class AnyCacheParams { + + public boolean hasMemoryCache = false; + public int memoryCacheMaxSize = 0; + public boolean hasDiskCache = false; + public File diskCacheDir = null; + public int diskCacheMaxSize = 0; + + /** + * Check AnyCacheParams is valid + * + * @throws IllegalStateException + */ + public void isValid() throws IllegalStateException { + if (!hasMemoryCache && !hasDiskCache) { + throw new IllegalStateException("No memory cache and no disk cache. What can I do for you?"); + } + + if (hasMemoryCache && memoryCacheMaxSize <= 0) { + throw new IllegalStateException("Memory cache max size must be bigger than 0."); + } + + if (hasDiskCache) { + if (diskCacheDir == null) { + throw new IllegalStateException("Disk cache dir can't be null."); + } + if (diskCacheMaxSize <= 0) { + throw new IllegalStateException("Disk cache max size must be bigger than 0."); + } + } + } + } + + public class MemoryCahce extends LruCache { public AnyCache mParent; @@ -298,12 +418,38 @@ public abstract class AnyCache { private static final int IO_BUFFER_SIZE = 8 * 1024; - public DiskLruCache mDiskLruCache; - public AnyCache mParent; + private DiskLruCache mDiskLruCache; + private AnyCache mParent; + + private File mCacheDir; + private int mMaxSize; public DiskCache(File cacheDir, int size, AnyCache parent) throws IOException { mDiskLruCache = DiskLruCache.open(cacheDir, 1, 1, size); mParent = parent; + + mCacheDir = cacheDir; + mMaxSize = size; + } + + public File getCacheDir() { + return mCacheDir; + } + + public int getMaxSize() { + return mMaxSize; + } + + public boolean isClosed() { + return mDiskLruCache.isClosed(); + } + + public void delete() throws IOException { + mDiskLruCache.delete(); + } + + public void flush() throws IOException { + mDiskLruCache.flush(); } public E get(String key) { @@ -347,7 +493,6 @@ public abstract class AnyCache { final BufferedOutputStream buffOut = new BufferedOutputStream(os, IO_BUFFER_SIZE); boolean result = mParent.write(buffOut, value); - mDiskLruCache.flush(); editor.commit(); return result; } else { diff --git a/app/src/main/java/com/hippo/ehviewer/cache/ImageCache.java b/app/src/main/java/com/hippo/ehviewer/cache/ImageCache.java index 345bdb27d..be91d9e30 100644 --- a/app/src/main/java/com/hippo/ehviewer/cache/ImageCache.java +++ b/app/src/main/java/com/hippo/ehviewer/cache/ImageCache.java @@ -49,25 +49,25 @@ public class ImageCache extends AnyCache{ public static @NonNull ImageCache getImageCache(@NonNull Context context) { if (sImageCache == null) { - sImageCache = new ImageCache(context.getApplicationContext()); + final ActivityManager activityManager = (ActivityManager)context + .getSystemService(Context.ACTIVITY_SERVICE); + final int memoryCacheMax = Math.round(MEM_CACHE_DIVIDER * activityManager.getMemoryClass() + * 1024 * 1024); + + AnyCacheParams params = new AnyCacheParams(); + params.hasMemoryCache = true; + params.memoryCacheMaxSize = memoryCacheMax; + params.hasDiskCache = true; + params.diskCacheDir = getDiskCacheDir(context, TAG); + params.diskCacheMaxSize = 20 * 1024 * 1024; + + sImageCache = new ImageCache(params); } return sImageCache; } - private ImageCache(Context context) { - final ActivityManager activityManager = (ActivityManager)context - .getSystemService(Context.ACTIVITY_SERVICE); - final int memoryCacheMax = Math.round(MEM_CACHE_DIVIDER * activityManager.getMemoryClass() - * 1024 * 1024); - setMemoryCache(memoryCacheMax); - - File diskCacheDir = getDiskCacheDir(context, TAG); - if (diskCacheDir != null) { - if (!diskCacheDir.exists()) { - diskCacheDir.mkdirs(); - } - setDiskCache(diskCacheDir, 20 * 1024 * 1024); - } + public ImageCache(AnyCacheParams params) { + super(params); } @Override diff --git a/app/src/main/java/com/hippo/ehviewer/ui/AbsActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/AbsActivity.java index 91a090ea9..2b01b4774 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/AbsActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/AbsActivity.java @@ -19,6 +19,7 @@ package com.hippo.ehviewer.ui; import android.app.Activity; import com.google.analytics.tracking.android.EasyTracker; +import com.hippo.ehviewer.cache.ImageCache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Ui; @@ -31,6 +32,13 @@ public abstract class AbsActivity extends Activity { Ui.adjustOrientation(this); } + @Override + protected void onPause() { + super.onPause(); + + ImageCache.getImageCache(this).flush(); + } + @Override protected void onStart() { super.onStart();