From ce2907610aac1a9bfd1c04b6ffcc3028f6830d95 Mon Sep 17 00:00:00 2001 From: seven332 Date: Mon, 23 Jun 2014 00:44:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=8D=A2=20cache=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=8D=A2=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E5=BB=BA=E7=AB=8B=20previewlist=20=E7=B1=BB=EF=BC=8C?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E4=B8=8D=E9=9C=80=E8=A6=81=E7=9A=84=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- res/raw/change_log | 1 + src/com/hippo/ehviewer/AppContext.java | 20 +- src/com/hippo/ehviewer/DiskCache.java | 322 ------ src/com/hippo/ehviewer/ImageGeterManager.java | 213 ---- src/com/hippo/ehviewer/ImageLoader.java | 176 ++++ src/com/hippo/ehviewer/StartActivity.java | 3 +- src/com/hippo/ehviewer/cache/ImageCache.java | 71 +- .../ehviewer/data/NormalPreviewList.java | 184 ++++ src/com/hippo/ehviewer/data/PreviewList.java | 98 +- .../hippo/ehviewer/ehclient/DetailParser.java | 22 +- src/com/hippo/ehviewer/ehclient/EhClient.java | 292 +----- src/com/hippo/ehviewer/ehclient/EhInfo.java | 4 +- .../{ => exception}/ParserException.java | 2 +- src/com/hippo/ehviewer/network/Constant.java | 6 +- .../hippo/ehviewer/network/Downloader.java | 5 +- .../hippo/ehviewer/network/HttpHelper.java | 53 +- .../ehviewer/network/PrefCookieHelper.java | 88 -- .../ehviewer/network/ShapreCookieStore.java | 379 ------- .../ehviewer/ui/AbstractFragmentActivity.java | 3 + .../ehviewer/ui/AbstractGalleryActivity.java | 42 +- .../ehviewer/ui/AbstractSlidingActivity.java | 3 + .../ehviewer/ui/DetailSectionFragment.java | 223 +--- .../hippo/ehviewer/ui/DownloadActivity.java | 43 +- .../hippo/ehviewer/ui/FavouriteActivity.java | 1 - .../hippo/ehviewer/ui/SettingsActivity.java | 11 +- src/com/hippo/ehviewer/util/Cache.java | 104 -- .../hippo/ehviewer/widget/LoadImageView.java | 57 +- .../disklrucache/DiskLruCache.java | 968 ------------------ .../disklrucache/StrictLineReader.java | 192 ---- src/com/jakewharton/disklrucache/Util.java | 77 -- 30 files changed, 580 insertions(+), 3083 deletions(-) delete mode 100644 src/com/hippo/ehviewer/DiskCache.java delete mode 100644 src/com/hippo/ehviewer/ImageGeterManager.java create mode 100644 src/com/hippo/ehviewer/ImageLoader.java create mode 100644 src/com/hippo/ehviewer/data/NormalPreviewList.java rename src/com/hippo/ehviewer/{ => exception}/ParserException.java (94%) delete mode 100644 src/com/hippo/ehviewer/network/PrefCookieHelper.java delete mode 100644 src/com/hippo/ehviewer/network/ShapreCookieStore.java delete mode 100644 src/com/hippo/ehviewer/util/Cache.java delete mode 100644 src/com/jakewharton/disklrucache/DiskLruCache.java delete mode 100644 src/com/jakewharton/disklrucache/StrictLineReader.java delete mode 100644 src/com/jakewharton/disklrucache/Util.java diff --git a/res/raw/change_log b/res/raw/change_log index 2048e1794..912c48223 100644 --- a/res/raw/change_log +++ b/res/raw/change_log @@ -1,6 +1,7 @@ Version 0.5.4 (2014-??-??) * 用户信息中显示用户名改为显示昵称 * 用户信息中显示头像 +* 显示登陆中的错误 Version 0.5.3 (2014-06-15) * 添加热门 diff --git a/src/com/hippo/ehviewer/AppContext.java b/src/com/hippo/ehviewer/AppContext.java index 2bce02fb6..df1113105 100644 --- a/src/com/hippo/ehviewer/AppContext.java +++ b/src/com/hippo/ehviewer/AppContext.java @@ -22,10 +22,10 @@ import java.lang.Thread.UncaughtExceptionHandler; import java.text.DateFormat; import java.text.SimpleDateFormat; +import com.hippo.ehviewer.cache.ImageCache; import com.hippo.ehviewer.data.Data; import com.hippo.ehviewer.ehclient.EhClient; import com.hippo.ehviewer.network.HttpHelper; -import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Crash; import com.hippo.ehviewer.util.Download; @@ -46,7 +46,6 @@ public class AppContext extends Application implements UncaughtExceptionHandler private Data mData; private EhClient mEhClient; - private ImageGeterManager mImageGeterManager; private ThreadPool mNetworkThreadPool; @Override @@ -58,15 +57,13 @@ public class AppContext extends Application implements UncaughtExceptionHandler Config.init(this); Ui.init(this); - Cache.init(this); Crash.init(this); mEhClient = new EhClient(this); Download.init(this); Favorite.init(this); mData = new Data(this); - mImageGeterManager = new ImageGeterManager(this, Cache.memoryCache, Cache.diskCache); - LoadImageView.setImageGeterManager(mImageGeterManager); + ImageLoader.createHandler(); HttpHelper.createHandler(); mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); @@ -96,14 +93,19 @@ public class AppContext extends Application implements UncaughtExceptionHandler return mData; } - public ImageGeterManager getImageGeterManager() { - return mImageGeterManager; - } - public DateFormat getDateFormat() { return mFormatter; } + /** + * {@inheritDoc} + */ + @Override + public void onLowMemory() { + ImageCache.getInstance(this).evictAll(); + super.onLowMemory(); + } + @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { diff --git a/src/com/hippo/ehviewer/DiskCache.java b/src/com/hippo/ehviewer/DiskCache.java deleted file mode 100644 index c502fb463..000000000 --- a/src/com/hippo/ehviewer/DiskCache.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2014 Hippo Seven - * - * 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.hippo.ehviewer; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import com.hippo.ehviewer.util.Cache; -import com.hippo.ehviewer.util.Ui; -import com.hippo.ehviewer.util.Util; -import com.jakewharton.disklrucache.DiskLruCache; - -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Movie; -import android.os.Environment; -import com.hippo.ehviewer.util.Log; - -// For Gallery cover key is gid, -// for example , gid is 618395, token is 0439fa3666, -// so key is 618395 - -// For Gallery preview key is gid-preview-num-row, -// for example , gid is 618395, token is 0439fa3666, page2 -// so key is 618395-preview-2-0 - -// For Gallery image key is gid-preview-num, -// for example , gid is 618395, token is 0439fa3666, image2 -// so key is 618395-image-2 - -public class DiskCache { - private static String TAG = "ImageDiskCache"; - - private static final int VALUE_IDX = 0; - - private Context mContext; - private BitmapFactory.Options opt; - private final DiskLruCache diskLruCache; - - public DiskCache(Context context, String path, long maxSize) throws NameNotFoundException, IOException { - this.mContext = context; - - opt = Ui.getBitmapOpt(); - if (!Cache.hasSdCard()) { - throw new IllegalStateException("Has no SdCard."); - } - - File dir = new File(Environment.getExternalStorageDirectory() + path); - int version = mContext.getPackageManager().getPackageInfo( - mContext.getPackageName(), 0).versionCode; - version = 1; - diskLruCache = DiskLruCache.open(dir, version, 1, maxSize); - } - - public long size() { - return diskLruCache.size(); - } - - public long maxSize() { - return diskLruCache.getMaxSize(); - } - - public void setMaxSize(long maxSize) { - diskLruCache.setMaxSize(maxSize); - } - - public void close() { - try { - diskLruCache.close(); - } catch (IOException e) { - Log.d(TAG, "diskLruCache close error !"); - } - } - - public boolean hasKey(String key) { - DiskLruCache.Snapshot snapshot = null; - try { - snapshot = diskLruCache.get(key); - } catch (IOException e) { - } - if(snapshot==null) - return false; - snapshot.close(); - return true; - } - - public Object get(String key, int type) { - DiskLruCache.Snapshot snapshot = null; - try { - snapshot = diskLruCache.get(key); - } catch (IOException e) { - } - if (snapshot == null) - return null; - InputStream is = snapshot.getInputStream(VALUE_IDX); - if (type == Util.BITMAP) { - Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt); - return bitmap; - } else if (type == Util.MOVIE) { - is = new BufferedInputStream(is, 16 * 1024); - is.mark(16 * 1024); - Movie movie = Movie.decodeStream(is); - return movie; - } - return null; - } - - public boolean put(String key, InputStream is) throws IOException { - DiskLruCache.Editor editor = diskLruCache.edit(key); - if (editor == null) - return false; - BufferedOutputStream bos = new BufferedOutputStream(editor.newOutputStream(VALUE_IDX)); - OutputStream os = new CacheOutputStream(bos, editor); - Util.copy(is, os); - return true; - } - - public void clear() { - try { - diskLruCache.delete(); - } catch (IOException e) { - } - } - - private class CacheOutputStream extends FilterOutputStream { - - private final DiskLruCache.Editor editor; - private boolean failed = false; - - private CacheOutputStream(OutputStream os, DiskLruCache.Editor editor) { - super(os); - this.editor = editor; - } - - @Override - public void close() throws IOException { - IOException closeException = null; - try { - super.close(); - } catch (IOException e) { - closeException = e; - } - - if (failed) { - editor.abort(); - } else { - editor.commit(); - } - - if (closeException != null) throw closeException; - } - - @Override - public void flush() throws IOException { - try { - super.flush(); - } catch (IOException e) { - failed = true; - throw e; - } - } - - @Override - public void write(int oneByte) throws IOException { - try { - super.write(oneByte); - } catch (IOException e) { - failed = true; - throw e; - } - } - - @Override - public void write(byte[] buffer) throws IOException { - try { - super.write(buffer); - } catch (IOException e) { - failed = true; - throw e; - } - } - - @Override - public void write(byte[] buffer, int offset, int length) throws IOException { - try { - super.write(buffer, offset, length); - } catch (IOException e) { - failed = true; - throw e; - } - } - } - /* - private Context context = null; - private File dir = null; - int maxSize = 1024 * 10; - - public DiskCache(Context context, String path, int maxSize) { - this.context = context; - this.maxSize = maxSize; - if (maxSize <= 0) - maxSize = 1024 * 10; - - File rootdir = Environment.getExternalStorageDirectory(); - dir = new File(rootdir + path); - dir.mkdirs(); - } - - public boolean hasKey(String key) { - synchronized (key) { - - File file = new File(dir, key); - if (file.exists()) { - if (file.isDirectory()) - file.delete(); - else - return true; - } - return false; - } - } - - public Object get(String key, int type) { - synchronized (key) { - File file = new File(dir, key); - if (!file.isFile()) - return null; - try { - InputStream is = new FileInputStream(file); - if (type == Util.BITMAP) { - Bitmap bitmap = BitmapFactory.decodeStream(is, null, Util.opt); - return bitmap; - } else if (type == Util.MOVIE) { - is = new BufferedInputStream(is, 16 * 1024); - is.mark(16 * 1024); - Movie movie = Movie.decodeStream(is); - return movie; - } - } catch (FileNotFoundException e) { - Log.d(TAG, "WTF, I have checked that the file does exists."); - e.printStackTrace(); - } - return null; - } - } - - public boolean put(String key, InputStream is) throws IOException { - synchronized (key) { - File file = new File(dir, key); - try { - file.delete(); - file.createNewFile(); - } catch (IOException e) { - dir.mkdirs(); - file.delete(); - try { - file.createNewFile(); - } catch (IOException e1) { - Log.d(TAG, "WTF, mkdirs didn't work? Path is " + file.getPath()); - e1.printStackTrace(); - return false; - } - } - try { - Util.inputStream2File(is, file); - return true; - } catch (IOException e) { - Log.d(TAG, "Put " + key + " error."); - throw e; - } - } - } - - public void clear() { - clearDirectory(dir); - } - - private void clearDirectory(File dir) { - - for (File file: dir.listFiles()) { - if (file.isDirectory()) clearDirectory(file); - file.delete(); - } - - }*/ - /* - * private static String getStingMD5(String s) { String re = null; try { - * MessageDigest messageDigest =MessageDigest.getInstance(Algorithm); byte[] - * inputByteArray = s.getBytes(); messageDigest.update(inputByteArray); - * byte[] resultByteArray = messageDigest.digest(); re = - * byteArrayToHex(resultByteArray); } catch (NoSuchAlgorithmException e) { - * e.printStackTrace(); Log.d(TAG, e.getMessage()); } return re; } - * - * private static String byteArrayToHex(byte[] byteArray) { char[] hexDigits - * = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' }; - * char[] resultCharArray =new char[byteArray.length * 2]; int index = 0; - * for (byte b : byteArray) { resultCharArray[index++] = hexDigits[b>>> 4 & - * 0xf]; resultCharArray[index++] = hexDigits[b& 0xf]; } return new - * String(resultCharArray); } - */ -} diff --git a/src/com/hippo/ehviewer/ImageGeterManager.java b/src/com/hippo/ehviewer/ImageGeterManager.java deleted file mode 100644 index bc4dcf871..000000000 --- a/src/com/hippo/ehviewer/ImageGeterManager.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2014 Hippo Seven - * - * 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.hippo.ehviewer; - -import java.util.Stack; - -import com.hippo.ehviewer.network.HttpHelper; -import com.hippo.ehviewer.util.Constants; -import com.hippo.ehviewer.util.Ui; -import com.hippo.ehviewer.util.Util; -import com.hippo.ehviewer.widget.LoadImageView; - -import android.content.Context; -import android.graphics.Bitmap; -import android.os.Handler; -import android.os.Message; -import android.support.v4.util.LruCache; - -import com.hippo.ehviewer.util.Log; - -public class ImageGeterManager { - private static final String TAG = "ImageGeterManager"; - - public static final int MEMORY_CACHE = 0x1; - public static final int DISK_CACHE = 0x2; - public static final int DOWNLOAD = 0x4; - - private class LoadTask { - public String url; - public String key; - public int mode; - public OnGetImageListener listener; - public Bitmap bitmap; - - public LoadTask(String url, String key, int mode, OnGetImageListener listener) { - this.url = url; - this.key = key; - this.mode = mode; - this.listener = listener; - } - } - private Context mContext; - - private final Stack mLoadCacheTask; - private ImageDownloadManager mImageDownloadTask; - - private LruCache mMemoryCache; - private DiskCache mDiskCache; - - private Object mLock; - - private static final Handler mHandler = - new Handler() { - @Override - public void handleMessage(Message msg) { - LoadTask task = (LoadTask)msg.obj; - if (msg.what == Constants.TRUE) { - task.listener.onGetImageSuccess(task.key, task.bitmap, msg.arg1); - } else if (msg.what == Constants.FALSE){ - task.listener.onGetImageFail(task.key); - } - } - }; - - public ImageGeterManager(Context context, LruCache memoryCache, - DiskCache diskCache) { - mLoadCacheTask = new Stack(); - mImageDownloadTask = new ImageDownloadManager(); - - mContext = context; - mMemoryCache = memoryCache; - mDiskCache = diskCache; - - mLock = new Object(); - new Thread(new LoadFromCacheTask()).start(); - } - - public void add(String url, String key, int mode, OnGetImageListener listener) { - synchronized (mLock) { - mLoadCacheTask.push(new LoadTask(url, key, mode, listener)); - mLock.notify(); - } - } - - private class LoadFromCacheTask implements Runnable { - @Override - public void run() { - LoadTask loadTask; - while (true) { - synchronized (mLock) { - if (mLoadCacheTask.isEmpty()) { - try { - mLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - continue; - } - loadTask = mLoadCacheTask.pop(); - } - - // Continue if do not need any more - if (!loadTask.listener.onGetImageStart(loadTask.key)) - continue; - - String key = loadTask.key; - int mode = loadTask.mode; - int getMode = MEMORY_CACHE; - if ((mode & MEMORY_CACHE) != 0 && mMemoryCache != null - && (loadTask.bitmap = mMemoryCache.get(key)) != null) - getMode = MEMORY_CACHE; - else if ((mode & DISK_CACHE) != 0 && mDiskCache != null - && (loadTask.bitmap = (Bitmap)mDiskCache.get(key, Util.BITMAP)) != null) { - getMode = DISK_CACHE; - if (mMemoryCache != null) - mMemoryCache.put(key, loadTask.bitmap); - } - - if (loadTask.bitmap != null) { // Get bitmap - Message msg = new Message(); - msg.obj = loadTask; - msg.what = Constants.TRUE; - msg.arg1 = getMode; - mHandler.sendMessage(msg); - } else { // get from cache miss - if ((mode & DOWNLOAD) != 0) { - mImageDownloadTask.add(loadTask); - } else { - Message msg = new Message(); - msg.obj = loadTask; - msg.what = Constants.FALSE; - mHandler.sendMessage(msg); - } - } - } - } - } - - private class ImageDownloadManager { - - private static final int MAX_DOWNLOAD_THREADS = 3; - - private final Stack mDownloadTask; - - private int workingDownloadThreads = 0; - - public ImageDownloadManager() { - mDownloadTask = new Stack(); - } - - public synchronized void add(LoadTask loadTask) { - mDownloadTask.push(loadTask); - if (workingDownloadThreads < MAX_DOWNLOAD_THREADS) { - new Thread(new DownloadImageTask()).start(); - workingDownloadThreads++; - } - } - - private class DownloadImageTask implements Runnable { - @Override - public void run() { - LoadTask loadTask; - HttpHelper httpHelper = new HttpHelper(mContext); - while (true) { - synchronized (ImageDownloadManager.this) { - if (mDownloadTask.isEmpty()) { - loadTask = null; - workingDownloadThreads--; - break; - } - loadTask = mDownloadTask.pop(); - } - - loadTask.bitmap = httpHelper.getImage(loadTask.url, - loadTask.key, mMemoryCache, mDiskCache, true); - - Message msg = new Message(); - msg.obj = loadTask; - if (loadTask.bitmap == null) { - msg.what = Constants.FALSE; - } else { - msg.what = Constants.TRUE; - msg.arg1 = DOWNLOAD; - } - mHandler.sendMessage(msg); - } - } - } - } - - public interface OnGetImageListener { - /** - * @return False if you wanna stop get - */ - boolean onGetImageStart(String key); - void onGetImageSuccess(String key, Bitmap bmp, int mode); - void onGetImageFail(String key); - } -} diff --git a/src/com/hippo/ehviewer/ImageLoader.java b/src/com/hippo/ehviewer/ImageLoader.java new file mode 100644 index 000000000..ca49c32f0 --- /dev/null +++ b/src/com/hippo/ehviewer/ImageLoader.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2014 Hippo Seven + * + * 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.hippo.ehviewer; + +import java.util.Stack; + +import com.hippo.ehviewer.cache.ImageCache; +import com.hippo.ehviewer.network.HttpHelper; + +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Message; + +public class ImageLoader { + private static final String TAG = ImageLoader.class.getSimpleName(); + + private static ImageLoader sInstance; + private static Handler mHandler; + + private class LoadTask { + public String url; + public String key; + public OnGetImageListener listener; + public Bitmap bitmap; + + public LoadTask(String url, String key, OnGetImageListener listener) { + this.url = url; + this.key = key; + this.listener = listener; + } + } + + private Context mContext; + private final Stack mLoadTasks; + private ImageCache mImageCache; + private ImageDownloader mImageDownloader; + private Object mLock; + + + public static final void createHandler() { + if (mHandler != null) + return; + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + LoadTask task = (LoadTask)msg.obj; + task.listener.onGetImage(task.key, task.bitmap); + } + }; + } + + public ImageLoader(Context context) { + mLoadTasks = new Stack(); + mImageDownloader = new ImageDownloader(); + + mContext = context; + mImageCache = ImageCache.getInstance(mContext); + + mLock = new Object(); + new Thread(new LoadFromCacheTask()).start(); + } + + public final static ImageLoader getInstance(final Context context) { + if (sInstance == null) { + sInstance = new ImageLoader(context.getApplicationContext()); + } + return sInstance; + } + + public void add(String url, String key, OnGetImageListener listener) { + synchronized (mLock) { + mLoadTasks.push(new LoadTask(url, key, listener)); + mLock.notify(); + } + } + + private class LoadFromCacheTask implements Runnable { + @Override + public void run() { + LoadTask loadTask; + while (true) { + synchronized (mLock) { + if (mLoadTasks.isEmpty()) { + try { + mLock.wait(); + } catch (InterruptedException e) {} + continue; + } + loadTask = mLoadTasks.pop(); + } + + String key = loadTask.key; + loadTask.bitmap = mImageCache.getCachedBitmap(key); + + if (loadTask.bitmap != null) { + Message msg = new Message(); + msg.obj = loadTask; + mHandler.sendMessage(msg); + } else { + mImageDownloader.add(loadTask); + } + } + } + } + + private class ImageDownloader { + private static final int MAX_DOWNLOAD_THREADS = 3; + private final Stack mDownloadTasks; + private int mWorkingThreadNum = 0; + private Object mLock; + + public ImageDownloader() { + mLock = new Object(); + mDownloadTasks = new Stack(); + } + + public void add(LoadTask loadTask) { + synchronized (mLock) { + mDownloadTasks.push(loadTask); + if (mWorkingThreadNum < MAX_DOWNLOAD_THREADS) { + new Thread(new DownloadImageTask()).start(); + mWorkingThreadNum++; + } + } + } + + private class DownloadImageTask implements Runnable { + @Override + public void run() { + LoadTask loadTask; + HttpHelper httpHelper = new HttpHelper(mContext); + while (true) { + synchronized (mLock) { + if (mDownloadTasks.isEmpty()) { + loadTask = null; + mWorkingThreadNum--; + break; + } + loadTask = mDownloadTasks.pop(); + } + + loadTask.bitmap = httpHelper.getImage(loadTask.url); + mImageCache.addBitmapToCache(loadTask.key, loadTask.bitmap); + + Message msg = new Message(); + msg.obj = loadTask; + mHandler.sendMessage(msg); + } + } + } + } + + public interface OnGetImageListener { + /** + * bmp is null for fail + * @param key + * @param bmp + */ + void onGetImage(String key, Bitmap bmp); + } +} diff --git a/src/com/hippo/ehviewer/StartActivity.java b/src/com/hippo/ehviewer/StartActivity.java index 328e7c2a0..d2b864b86 100644 --- a/src/com/hippo/ehviewer/StartActivity.java +++ b/src/com/hippo/ehviewer/StartActivity.java @@ -17,7 +17,6 @@ package com.hippo.ehviewer; import com.hippo.ehviewer.ui.MangaListActivity; -import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Crash; import com.hippo.ehviewer.widget.AlertButton; @@ -252,7 +251,7 @@ public class StartActivity extends Activity { return; } case CHECK_EXTERNAL_STORAGE: - if (!Cache.hasSdCard()) { + if (false) { createNoSdCardDialog().show(); return; } diff --git a/src/com/hippo/ehviewer/cache/ImageCache.java b/src/com/hippo/ehviewer/cache/ImageCache.java index 0692c2b0b..9ec965728 100644 --- a/src/com/hippo/ehviewer/cache/ImageCache.java +++ b/src/com/hippo/ehviewer/cache/ImageCache.java @@ -48,12 +48,7 @@ import com.hippo.ehviewer.util.Util; public final class ImageCache { private static final String TAG = ImageCache.class.getSimpleName(); - - /** - * The {@link Uri} used to retrieve album art - */ - private static final Uri mArtworkUri; - + /** * Default memory cache size as a percent of device memory class */ @@ -96,11 +91,7 @@ public final class ImageCache { */ public boolean mPauseDiskAccess = false; private Object mPauseLock = new Object(); - - static { - mArtworkUri = Uri.parse("content://media/external/audio/albumart"); - } - + /** * Constructor of ImageCache * @@ -413,63 +404,7 @@ public final class ImageCache { } return null; } - - /** - * Tries to return the album art from memory cache and disk cache, before - * calling {@code #getArtworkFromFile(Context, String)} again - * - * @param context The {@link Context} to use - * @param data The name of the album art - * @param id The ID of the album to find artwork for - * @return The artwork for an album - */ - public final Bitmap getCachedArtwork(final Context context, final String data, final long id) { - if (context == null || data == null) { - return null; - } - Bitmap cachedImage = getCachedBitmap(data); - if (cachedImage == null && id >= 0) { - cachedImage = getArtworkFromFile(context, id); - } - if (cachedImage != null) { - addBitmapToMemCache(data, cachedImage); - return cachedImage; - } - return null; - } - - /** - * Used to fetch the artwork for an album locally from the user's device - * - * @param context The {@link Context} to use - * @param albumID The ID of the album to find artwork for - * @return The artwork for an album - */ - public final Bitmap getArtworkFromFile(final Context context, final long albumId) { - if (albumId < 0) { - return null; - } - Bitmap artwork = null; - waitUntilUnpaused(); - try { - final Uri uri = ContentUris.withAppendedId(mArtworkUri, albumId); - final ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver() - .openFileDescriptor(uri, "r"); - if (parcelFileDescriptor != null) { - final FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); - artwork = BitmapFactory.decodeFileDescriptor(fileDescriptor); - } - } catch (final IllegalStateException e) { - // Log.e(TAG, "IllegalStateExcetpion - getArtworkFromFile - ", e); - } catch (final FileNotFoundException e) { - // Log.e(TAG, "FileNotFoundException - getArtworkFromFile - ", e); - } catch (final OutOfMemoryError evict) { - // Log.e(TAG, "OutOfMemoryError - getArtworkFromFile - ", evict); - evictAll(); - } - return artwork; - } - + /** * flush() is called to synchronize up other methods that are accessing the * cache first diff --git a/src/com/hippo/ehviewer/data/NormalPreviewList.java b/src/com/hippo/ehviewer/data/NormalPreviewList.java new file mode 100644 index 000000000..f0d585613 --- /dev/null +++ b/src/com/hippo/ehviewer/data/NormalPreviewList.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014 Hippo Seven + * + * 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.hippo.ehviewer.data; + +import java.util.ArrayList; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.view.Gravity; +import android.view.View; +import android.view.View.OnClickListener; + +import com.hippo.ehviewer.ImageLoader; +import com.hippo.ehviewer.ui.MangaActivity; +import com.hippo.ehviewer.util.Ui; +import com.hippo.ehviewer.widget.AutoWrapLayout; + +public class NormalPreviewList extends PreviewList{ + + public class Item { + public int xOffset; + public int yOffset; + public int width; + public int height; + public String url; + + public Item(int xOffset, int yOffset, int width, int height, String url) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.width = width; + this.height = height; + this.url = url; + } + } + + public class Row { + public String imageUrl; + public ArrayList itemArray = new ArrayList(); + public int startIndex; + public Row(String imageUrl) { + this.imageUrl = imageUrl; + } + + public void addItem(int xOffset, int yOffset, int width, int height, + String url) { + itemArray.add(new Item(xOffset, yOffset, width, height, url)); + } + } + + private Row curRow; + public ArrayList rowArray = new ArrayList(); + + public void addItem(String imageUrl, String xOffset, String yOffset, String width, String height, + String url) { + if (curRow == null) { + curRow = new Row(imageUrl); + curRow.startIndex = 0; + rowArray.add(curRow); + } else if (!curRow.imageUrl.equals(imageUrl)) { + Row lastRow = curRow; + curRow = new Row(imageUrl); + curRow.startIndex = lastRow.startIndex + lastRow.itemArray.size(); + rowArray.add(curRow); + } + + curRow.addItem(Integer.parseInt(xOffset), + Integer.parseInt(yOffset), Integer.parseInt(width), + Integer.parseInt(height), url); + } + + public int getSum() { + int sum = 0; + for (Row row : rowArray) + sum += row.itemArray.size(); + return sum; + } + + // TODO reuse the TextView in AutoWrapLayout + @Override + public void addPreview(AutoWrapLayout viewGroup) { + if (mTargetPage != mHolder.getCurPreviewPage()) + return; + + int index = mTargetPage * mGi.previewPerPage + 1; // it is display index + int rowIndex = 0; + for (NormalPreviewList.Row row : rowArray) { + for (NormalPreviewList.Item item : row.itemArray) { + TextViewWithUrl tvu = new TextViewWithUrl(mActivity); + tvu.url = item.url; + tvu.setGravity(Gravity.CENTER); + tvu.setText(String.valueOf(index)); + final int finalIndex = index; + tvu.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + // Add to read in Data + Intent intent = new Intent(mActivity, + MangaActivity.class); + intent.putExtra("url", ((TextViewWithUrl)v).url); + intent.putExtra("gid", mGi.gid); + intent.putExtra("title", mGi.title); + intent.putExtra("firstPage", finalIndex - 1); + intent.putExtra("pageSum", mGi.pages); + mActivity.startActivity(intent); + } + }); + // Set transport drawable for temp + ColorDrawable white = new ColorDrawable(Color.TRANSPARENT); + white.setBounds(0, 0, item.width, item.height); + tvu.setCompoundDrawables(null, white, null, null); + + AutoWrapLayout.LayoutParams lp = new AutoWrapLayout.LayoutParams(); + lp.leftMargin = Ui.dp2pix(8); + lp.topMargin = Ui.dp2pix(8); + lp.rightMargin = Ui.dp2pix(8); + lp.bottomMargin = Ui.dp2pix(8); + viewGroup.addView(tvu, lp); + + index++; + } + ImageLoader.getInstance(mActivity).add(row.imageUrl, mGi.gid + "preview" + "m" + rowIndex, + new PreviewImageGetListener(viewGroup, rowIndex)); + rowIndex++; + } + } + + private class PreviewImageGetListener implements ImageLoader.OnGetImageListener { + private AutoWrapLayout mViewGroup; + private int mRowIndex; + + public PreviewImageGetListener(AutoWrapLayout viewGroup, int rowIndex) { + mViewGroup = viewGroup; + mRowIndex = rowIndex; + } + + @Override + public void onGetImage(String key, Bitmap bmp) { + if (mTargetPage != mHolder.getCurPreviewPage()) + return; + + if (bmp == null) { + mHolder.onGetPreviewImageFailure(); + } else { + int maxWidth = bmp.getWidth(); + int maxHeight = bmp.getHeight(); + + NormalPreviewList.Row row = rowArray.get(mRowIndex); + + int i = row.startIndex; + for(Item item : row.itemArray) { + if (item.xOffset + item.width > maxWidth) + item.width = maxWidth - item.xOffset; + if (item.yOffset + item.height > maxHeight) + item.height = maxHeight - item.yOffset; + BitmapDrawable bitmapDrawable = new BitmapDrawable( + mActivity.getResources(), Bitmap.createBitmap(bmp, + item.xOffset, item.yOffset, item.width, item.height)); + bitmapDrawable.setBounds(0, 0, item.width, item.height); + + TextViewWithUrl tvu = (TextViewWithUrl)mViewGroup.getChildAt(i); + tvu.setCompoundDrawables(null, bitmapDrawable, null, null); + i++; + } + } + } + } +} diff --git a/src/com/hippo/ehviewer/data/PreviewList.java b/src/com/hippo/ehviewer/data/PreviewList.java index 92653d972..e344563b5 100644 --- a/src/com/hippo/ehviewer/data/PreviewList.java +++ b/src/com/hippo/ehviewer/data/PreviewList.java @@ -16,66 +16,54 @@ package com.hippo.ehviewer.data; -import java.util.ArrayList; +import android.app.Activity; +import android.content.Context; +import android.widget.TextView; -public class PreviewList { +import com.hippo.ehviewer.ui.DetailSectionFragment; +import com.hippo.ehviewer.widget.AutoWrapLayout; + +/** + * This interface describe the previews in one page + * + * @author Hippo + * + */ +public abstract class PreviewList { - public class Row { + protected PreviewHolder mHolder; + protected Activity mActivity; + protected GalleryDetail mGi; + protected int mTargetPage; + + /** + * Add preview to view group + * @param viewGroup + * @return + */ + public abstract void addPreview(AutoWrapLayout viewGroup); + + public void setData(PreviewHolder holder, Activity activity, GalleryDetail gi, int targetPage) { + mHolder = holder; + mActivity = activity; + mGi = gi; + mTargetPage = targetPage; + } + + public void setTargetPage(int targetPage) { + mTargetPage = targetPage; + } + + protected class TextViewWithUrl extends TextView { + public String url; - public class Item { - public int xOffset; - public int yOffset; - public int width; - public int height; - public String url; - - public Item(int xOffset, int yOffset, int width, int height, String url) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.width = width; - this.height = height; - this.url = url; - } - } - - public String imageUrl; - public ArrayList itemArray = new ArrayList(); - public int startIndex; - public Row(String imageUrl) { - this.imageUrl = imageUrl; - } - - public void addItem(int xOffset, int yOffset, int width, int height, - String url) { - itemArray.add(new Item(xOffset, yOffset, width, height, url)); + public TextViewWithUrl(Context context) { + super(context); } } - private Row curRow; - public ArrayList rowArray = new ArrayList(); - - public void addItem(String imageUrl, String xOffset, String yOffset, String width, String height, - String url) { - if (curRow == null) { - curRow = new Row(imageUrl); - curRow.startIndex = 0; - rowArray.add(curRow); - } else if (!curRow.imageUrl.equals(imageUrl)) { - Row lastRow = curRow; - curRow = new Row(imageUrl); - curRow.startIndex = lastRow.startIndex + lastRow.itemArray.size(); - rowArray.add(curRow); - } - - curRow.addItem(Integer.parseInt(xOffset), - Integer.parseInt(yOffset), Integer.parseInt(width), - Integer.parseInt(height), url); - } - - public int getSum() { - int sum = 0; - for (Row row : rowArray) - sum += row.itemArray.size(); - return sum; + public interface PreviewHolder { + public int getCurPreviewPage(); + public void onGetPreviewImageFailure(); } } diff --git a/src/com/hippo/ehviewer/ehclient/DetailParser.java b/src/com/hippo/ehviewer/ehclient/DetailParser.java index 1a80a9631..bbbbd41de 100644 --- a/src/com/hippo/ehviewer/ehclient/DetailParser.java +++ b/src/com/hippo/ehviewer/ehclient/DetailParser.java @@ -26,7 +26,7 @@ import java.util.regex.Pattern; import com.hippo.ehviewer.ListUrls; import com.hippo.ehviewer.data.Comment; -import com.hippo.ehviewer.data.PreviewList; +import com.hippo.ehviewer.data.NormalPreviewList; import com.hippo.ehviewer.util.Log; public class DetailParser { @@ -66,23 +66,23 @@ public class DetailParser { public int previewPerPage; public int previewSum; public LinkedHashMap>> tags; - public PreviewList previewList; + public NormalPreviewList previewList; public LinkedList comments; public void setMode(int mode) { mMode = mode; } - public int parser(String pageContent) { + public int parser(String body) { int re = 0; Pattern p; Matcher m; - if (pageContent.contains(OFFENSIVE_STRING)) { + if (body.contains(OFFENSIVE_STRING)) { return OFFENSIVE; } - if (pageContent.contains(PINING_STRING)) { + if (body.contains(PINING_STRING)) { return PINING; } @@ -111,7 +111,7 @@ public class DetailParser { + "]*>([^<>]+)" // rating + ".+" + "
]*>(?:]*>)?]*href=\"([^<>\"]+)\"[^<>]*>"); // get firstPage - m = p.matcher(pageContent); + m = p.matcher(body); if (m.find()) { re |= DETAIL; @@ -144,7 +144,7 @@ public class DetailParser { tags = new LinkedHashMap>>(); p = Pattern .compile("]*>([^<>]+):(?:]*>]*>[^<>]*[^<>]*]*>\\d+[^<>]*
)+"); - m = p.matcher(pageContent); + m = p.matcher(body); while (m.find()) { re |= TAG; String groupName = m.group(1); @@ -158,7 +158,7 @@ public class DetailParser { // Get preview info if ((mMode & PREVIEW_INFO) != 0) { p = Pattern.compile("

Showing ([\\d|,]+) - ([\\d|,]+) of ([\\d|,]+) images

"); - m = p.matcher(pageContent); + m = p.matcher(body); if (m.find()) { re |= PREVIEW_INFO; previewPerPage = Integer.parseInt(m.group(2).replace(",", @@ -173,11 +173,11 @@ public class DetailParser { if ((mMode & PREVIEW) != 0) { p = Pattern .compile("]*class=\"gdtm\"[^<>]*>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*>]*href=\"(.+?)\"[^<>]*>"); - m = p.matcher(pageContent); + m = p.matcher(body); while (m.find()) { if (previewList == null) { re |= PREVIEW; - previewList = new PreviewList(); + previewList = new NormalPreviewList(); } previewList.addItem(m.group(3), m.group(4), "0", m.group(1), m.group(2), m.group(5)); @@ -187,7 +187,7 @@ public class DetailParser { if ((mMode & COMMENT) != 0) { p = Pattern .compile("
Posted on ([^<>]+) by ]+>([^<>]+).*?
(.*?)
"); - m = p.matcher(pageContent); + m = p.matcher(body); comments = new LinkedList(); while (m.find()) { re |= COMMENT; diff --git a/src/com/hippo/ehviewer/ehclient/EhClient.java b/src/com/hippo/ehviewer/ehclient/EhClient.java index adccd0467..c1e4ff14c 100644 --- a/src/com/hippo/ehviewer/ehclient/EhClient.java +++ b/src/com/hippo/ehviewer/ehclient/EhClient.java @@ -16,37 +16,27 @@ package com.hippo.ehviewer.ehclient; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; import java.net.MalformedURLException; -import java.net.URL; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.http.conn.ConnectTimeoutException; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import com.hippo.ehviewer.Analytics; import com.hippo.ehviewer.AppContext; -import com.hippo.ehviewer.DiskCache; import com.hippo.ehviewer.ListUrls; import com.hippo.ehviewer.R; import com.hippo.ehviewer.data.Comment; import com.hippo.ehviewer.data.GalleryDetail; import com.hippo.ehviewer.data.GalleryInfo; import com.hippo.ehviewer.data.GalleryPopular; -import com.hippo.ehviewer.data.PreviewList; +import com.hippo.ehviewer.data.NormalPreviewList; import com.hippo.ehviewer.gallery.data.ImageSet; import com.hippo.ehviewer.network.Downloader; import com.hippo.ehviewer.network.HttpHelper; @@ -56,11 +46,8 @@ import com.hippo.ehviewer.util.ThreadPool.Job; import com.hippo.ehviewer.util.ThreadPool.JobContext; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Movie; import android.os.Handler; import android.os.Message; -import android.support.v4.util.LruCache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Download; @@ -68,7 +55,6 @@ import com.hippo.ehviewer.util.Future; import com.hippo.ehviewer.util.FutureListener; import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.util.ThreadPool; -import com.hippo.ehviewer.util.Ui; import com.hippo.ehviewer.util.Util; public class EhClient { @@ -188,11 +174,6 @@ public class EhClient { } } - public interface OnGetPageListListener { - public void onSuccess(Object checkFlag, PreviewList pageList); - public void onFailure(Object checkFlag, String eMsg); - } - public interface OnGetMangaUrlListener { public void onSuccess(Object checkFlag, String[] arg); public void onFailure(Object checkFlag, String eMsg); @@ -264,15 +245,6 @@ public class EhClient { switch (msg.what) { - case GET_PAGE_LIST: - GetPageListPackage getPageListPackage = (GetPageListPackage) msg.obj; - OnGetPageListListener listener6 = getPageListPackage.listener; - if (getPageListPackage.pageList != null) - listener6.onSuccess(getPageListPackage.checkFlag, getPageListPackage.pageList); - else - listener6.onFailure(getPageListPackage.checkFlag, getPageListPackage.eMsg); - break; - case GET_MANGA_URL: GetMangaUrlPackage getMangaUrlPackage = (GetMangaUrlPackage) msg.obj; OnGetMangaUrlListener listener7 = getMangaUrlPackage.listener; @@ -360,7 +332,7 @@ public class EhClient { } String avatarUrl = m.group(1); // Get avatar - Bitmap avatar = hp.getImage(avatarUrl, null, null, null, true); + Bitmap avatar = hp.getImage(avatarUrl); // Set avatar if not null if (avatar != null) mInfo.setAvatar(avatar); @@ -409,7 +381,7 @@ public class EhClient { }).start(); } - // Get Manga Detail + // Get gallery Detail public interface OnGetGDetailListener { public void onSuccess(GalleryDetail md); public void onFailure(String eMsg); @@ -456,7 +428,7 @@ public class EhClient { md.previewSum = parser.previewSum; md.tags = parser.tags; - md.previewLists = new PreviewList[md.previewSum]; + md.previewLists = new NormalPreviewList[md.previewSum]; md.previewLists[0] = parser.previewList; md.comments = parser.comments; listener.onSuccess(md); @@ -474,83 +446,39 @@ public class EhClient { }).start(); } - // Get page list - private class GetPageListPackage { - public Object checkFlag; - public PreviewList pageList; - public OnGetPageListListener listener; - public String eMsg; - - public GetPageListPackage(Object checkFlag, PreviewList pageList, OnGetPageListListener listener, - String eMsg) { - this.checkFlag = checkFlag; - this.pageList = pageList; - this.listener = listener; - this.eMsg = eMsg; - } + // Get preview list + public interface OnGetPreviewListListener { + public void onSuccess(Object checkFlag, NormalPreviewList pageList); + public void onFailure(Object checkFlag, String eMsg); } - private class GetPageListRunnable implements Runnable { - private String url; - - public PreviewList pageList; - public String eMsg; - - public GetPageListRunnable(String url) { - this.url = url; - } - - @Override - public void run() { - pageList = null; - - HttpHelper hp = new HttpHelper(mAppContext); - String pageContent = hp.get(url); - if (pageContent != null) { - - pageList = getPageList(pageContent); - if (pageList == null) - eMsg = mAppContext.getString(R.string.em_parser_error); - } else - eMsg = hp.getEMsg(); - } - } - - public void getPageList(String url, final Object checkFlag, - final OnGetPageListListener listener) { - - final GetPageListRunnable task = new GetPageListRunnable(url); - mThreadPool.submit(new Job() { + public void getPreviewList(final String url, final Object checkFlag, + final OnGetPreviewListListener listener) { + new Thread(new Runnable() { @Override - public Object run(JobContext jc) { - task.run(); - return null; + public void run() { + HttpHelper hp = new HttpHelper(mAppContext); + hp.setOnRespondListener(new HttpHelper.OnRespondListener() { + @Override + public void onSuccess(String body) { + DetailParser parser = new DetailParser(); + parser.setMode(DetailParser.PREVIEW); + if (parser.parser(body) == DetailParser.PREVIEW) { + listener.onSuccess(checkFlag, parser.previewList); + } else { + listener.onFailure(checkFlag, "Parser error"); + } + } + @Override + public void onFailure(String eMsg) { + listener.onFailure(checkFlag, eMsg); + } + }); + hp.get(url); } - }, new FutureListener() { - @Override - public void onFutureDone(Future future) { - Message msg = new Message(); - msg.what = GET_PAGE_LIST; - msg.obj = new GetPageListPackage(checkFlag, task.pageList, listener, task.eMsg); - mHandler.sendMessage(msg); - } - }); + }).start(); } - - private PreviewList getPageList(String pageContent) { - PreviewList pageList = null; - Pattern p = Pattern - .compile("]*class=\"gdtm\"[^<>]*>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*>]*href=\"(.+?)\"[^<>]*>"); - Matcher m = p.matcher(pageContent); - while (m.find()) { - if (pageList == null) - pageList = new PreviewList(); - pageList.addItem(m.group(3), m.group(4), "0", m.group(1), - m.group(2), m.group(5)); - } - return pageList; - } - + // Get Manga url and next page private class GetMangaUrlPackage { public Object checkFlag; @@ -624,162 +552,6 @@ public class EhClient { } }); } - - // Get image - private static class GetImagePackage { - public Object res; - public Object checkFlag; - public OnGetImageListener listener; - - public GetImagePackage(Object res, Object checkFlag, - OnGetImageListener listener) { - this.res = res; - this.checkFlag = checkFlag; - this.listener = listener; - } - } - - private static Handler getGetImageHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - OnGetImageListener listener = ((GetImagePackage) msg.obj).listener; - Object checkFlag = ((GetImagePackage) msg.obj).checkFlag; - Object res = ((GetImagePackage) msg.obj).res; - if (res == null) { - listener.onFailure(msg.what); - } - else - listener.onSuccess(checkFlag, res); - }; - }; - - private static class GetImageRunnable implements Runnable { - private String url; - private String key; - private int type; - private LruCache memoryCache; - private DiskCache diskCache; - private Object checkFlag; - private OnGetImageListener listener; - - public GetImageRunnable(String url, String key, int type, - LruCache memoryCache, DiskCache diskCache, - Object checkFlag, OnGetImageListener listener) { - this.url = url; - this.key = key; - this.type = type; - this.memoryCache = memoryCache; - this.diskCache = diskCache; - this.checkFlag = checkFlag; - this.listener = listener; - } - - @Override - public void run() { - int errorMessageId = R.string.em_unknown_error; - Object res = null; - synchronized (url) { - // Check memory cache - if (type == Util.BITMAP && memoryCache != null - && (res = memoryCache.get(key)) != null) { - sendMessage(res, errorMessageId); - return; - } - // If not find in memory cache or do not have memory cache - // Check disk cache - if (diskCache != null - && (res = diskCache.get(key, type)) != null) { - sendMessage(res, errorMessageId); - if (memoryCache != null && res instanceof Bitmap) - memoryCache.put(key, (Bitmap) res); - return; - } - Log.d(TAG, "Download image " + url); - - HttpURLConnection conn = null; - ByteArrayOutputStream baos = null; - try { - URL url = new URL(this.url); - conn = (HttpURLConnection) url.openConnection(); - conn.setConnectTimeout(5 * 1000); - conn.setReadTimeout(5 * 1000); - conn.connect(); - InputStream is = conn.getInputStream(); - if (diskCache != null) { - - int length = conn.getContentLength(); - if (length >= 0) - baos = new ByteArrayOutputStream(length); - else - baos = new ByteArrayOutputStream(); - Util.copy(is, baos); - byte[] bytes = baos.toByteArray(); - // To disk cache - is = new ByteArrayInputStream(bytes); - diskCache.put(key, is); - // Read - is = new ByteArrayInputStream(bytes); - is.reset(); - if (type == Util.BITMAP) { - res = BitmapFactory.decodeStream(is, null, - Ui.getBitmapOpt()); - if (memoryCache != null && res != null) - memoryCache.put(key, (Bitmap) res); - } else if (type == Util.MOVIE) { - is = new BufferedInputStream(is, 16 * 1024); - is.mark(16 * 1024); - res = Movie.decodeStream(is); - } - is.close(); - } else { - if (type == Util.BITMAP) { - res = BitmapFactory.decodeStream(is, null, - Ui.getBitmapOpt()); - if (memoryCache != null && res != null) - memoryCache.put(key, (Bitmap) res); - } else if (type == Util.MOVIE) { - is = new BufferedInputStream(is, 16 * 1024); - is.mark(16 * 1024); - res = Movie.decodeStream(is); - } - } - } catch (MalformedURLException e) { - errorMessageId = R.string.em_url_error; - e.printStackTrace(); - } catch (ConnectTimeoutException e) { - errorMessageId = R.string.em_timeout; - e.printStackTrace(); - } catch (UnknownHostException e) { - errorMessageId = R.string.em_no_network_2; - e.printStackTrace(); - } catch (IOException e) { - errorMessageId = R.string.em_network_error; - e.printStackTrace(); - } finally { - if (conn != null) - conn.disconnect(); - if (baos != null) - Util.closeStreamQuietly(baos); - } - sendMessage(res, errorMessageId); - } - } - - private void sendMessage(Object res, int errorMessageId) { - Message msg = new Message(); - msg.what = errorMessageId; - msg.obj = new GetImagePackage(res, checkFlag, listener); - getGetImageHandler.sendMessage(msg); - } - } - - public static void getImage(String url, String key, int type, - LruCache memoryCache, DiskCache diskCache, - Object checkFlag, OnGetImageListener listener) { - new Thread(new GetImageRunnable(url, key, type, memoryCache, diskCache, - checkFlag, listener)).start(); - } - public interface OnDownloadMangaListener { public void onDownloadMangaStart(String id); diff --git a/src/com/hippo/ehviewer/ehclient/EhInfo.java b/src/com/hippo/ehviewer/ehclient/EhInfo.java index f8e00e10d..5f90cd8b6 100644 --- a/src/com/hippo/ehviewer/ehclient/EhInfo.java +++ b/src/com/hippo/ehviewer/ehclient/EhInfo.java @@ -171,9 +171,11 @@ public class EhInfo { public void storeCookie(HttpURLConnection conn) { String ipb_member_id; String ipb_pass_hash; - SharedPreferences.Editor editor = mInfoPref.edit(); List cookieList = conn.getHeaderFields().get("Set-Cookie"); + if (cookieList == null) + return; + SharedPreferences.Editor editor = mInfoPref.edit(); for (String str : cookieList) { ipb_member_id = getCookie(str, "ipb_member_id"); ipb_pass_hash = getCookie(str, "ipb_pass_hash"); diff --git a/src/com/hippo/ehviewer/ParserException.java b/src/com/hippo/ehviewer/exception/ParserException.java similarity index 94% rename from src/com/hippo/ehviewer/ParserException.java rename to src/com/hippo/ehviewer/exception/ParserException.java index 7a0e95830..53ed894ae 100644 --- a/src/com/hippo/ehviewer/ParserException.java +++ b/src/com/hippo/ehviewer/exception/ParserException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.hippo.ehviewer; +package com.hippo.ehviewer.exception; public class ParserException extends Exception{ diff --git a/src/com/hippo/ehviewer/network/Constant.java b/src/com/hippo/ehviewer/network/Constant.java index 80ca8df33..6b22da9a4 100644 --- a/src/com/hippo/ehviewer/network/Constant.java +++ b/src/com/hippo/ehviewer/network/Constant.java @@ -17,14 +17,10 @@ package com.hippo.ehviewer.network; public class Constant { - public static final int HTTP_TEMP_REDIRECT = 307; - public static String defaultUserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36"; public static String userAgent = System.getProperty("http.agent", defaultUserAgent); - public static final int DEFAULT_TIMEOUT = 5 * 1000; + public static final int DEFAULT_TIMEOUT = 10 * 1000; public static final int MAX_REDIRECTS = 5; - public static final int BUFFER_SIZE = 4096; - } diff --git a/src/com/hippo/ehviewer/network/Downloader.java b/src/com/hippo/ehviewer/network/Downloader.java index e0fccfd0d..1ae1c7794 100644 --- a/src/com/hippo/ehviewer/network/Downloader.java +++ b/src/com/hippo/ehviewer/network/Downloader.java @@ -31,15 +31,14 @@ import java.net.UnknownHostException; import org.apache.http.conn.ConnectTimeoutException; import android.content.Context; -import com.hippo.ehviewer.util.Log; +import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.R; import com.hippo.ehviewer.exception.FileException; import com.hippo.ehviewer.exception.NoSdCardException; import com.hippo.ehviewer.exception.RedirectionException; import com.hippo.ehviewer.exception.ResponseCodeException; import com.hippo.ehviewer.exception.StopRequestException; -import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Util; // TODO 添加检查次磁盘空间 @@ -170,7 +169,7 @@ public class Downloader implements Runnable { @Override public void run() { int retryTimes = 0; - if (Cache.hasSdCard()) { + if (true) { boolean checkFolder = false; diff --git a/src/com/hippo/ehviewer/network/HttpHelper.java b/src/com/hippo/ehviewer/network/HttpHelper.java index 52fd88709..dd8647346 100644 --- a/src/com/hippo/ehviewer/network/HttpHelper.java +++ b/src/com/hippo/ehviewer/network/HttpHelper.java @@ -39,7 +39,6 @@ import java.util.zip.GZIPInputStream; import org.apache.http.conn.ConnectTimeoutException; import org.json.JSONObject; -import com.hippo.ehviewer.DiskCache; import com.hippo.ehviewer.R; import com.hippo.ehviewer.ehclient.EhClient; import com.hippo.ehviewer.ehclient.EhInfo; @@ -55,7 +54,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; -import android.support.v4.util.LruCache; import com.hippo.ehviewer.util.Log; @@ -441,68 +439,29 @@ public class HttpHelper { return requst(new PostJsonHelper(json), url); } - public Bitmap getImage(String urlStr, String key, - LruCache memoryCache, - DiskCache diskCache, boolean getImage) { + public Bitmap getImage(String urlStr) { mException = null; int redirectionCount = 0; URL url = null; HttpURLConnection conn = null; - ByteArrayOutputStream baos = null; - InputStream is = null; try { - - Log.d(TAG, "Http get bitmap " + urlStr); - + Log.d(TAG, "Http get image " + urlStr); url = new URL(urlStr); while (redirectionCount++ < Constant.MAX_REDIRECTS) { conn = (HttpURLConnection)url.openConnection(); conn.setRequestProperty("User-Agent", Constant.userAgent); conn.setConnectTimeout(Constant.DEFAULT_TIMEOUT); conn.setReadTimeout(Constant.DEFAULT_TIMEOUT); - conn.setRequestProperty("Connection", "close"); + conn.setRequestMethod("GET"); conn.connect(); final int responseCode = conn.getResponseCode(); switch (responseCode) { case HttpURLConnection.HTTP_OK: case HttpURLConnection.HTTP_PARTIAL: - - Bitmap bitmap = null; - is = conn.getInputStream(); - if (diskCache == null) { - if (getImage - && (bitmap = BitmapFactory.decodeStream(is, null, Ui.getBitmapOpt())) != null) { - if (memoryCache != null) - memoryCache.put(key, bitmap); - } - } else { - boolean twice = memoryCache != null || getImage; - if (twice) { - baos = new ByteArrayOutputStream(); - Util.copy(is, baos); - byte[] bytes = baos.toByteArray(); - // To disk cache - is = new ByteArrayInputStream(bytes); - diskCache.put(key, is); - is.close(); - // - is = new ByteArrayInputStream(bytes); - Bitmap bmp = BitmapFactory.decodeStream(is, null, Ui.getBitmapOpt()); - if (bmp != null) { - if (memoryCache != null) - memoryCache.put(key, bmp); - if (getImage) - bitmap = bmp; - } - is.close(); - baos.close(); - } else { - diskCache.put(key, is); - } - } + Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream(), null, Ui.getBitmapOpt()); return bitmap; case HttpURLConnection.HTTP_MOVED_PERM: @@ -522,10 +481,6 @@ public class HttpHelper { e.printStackTrace(); return null; } finally { - if (baos != null) - Util.closeStreamQuietly(baos); - if (is != null) - Util.closeStreamQuietly(is); if (conn != null) conn.disconnect(); } diff --git a/src/com/hippo/ehviewer/network/PrefCookieHelper.java b/src/com/hippo/ehviewer/network/PrefCookieHelper.java deleted file mode 100644 index ea0da56f1..000000000 --- a/src/com/hippo/ehviewer/network/PrefCookieHelper.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2014 Hippo Seven - * - * 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.hippo.ehviewer.network; - -import java.net.CookieStore; -import java.net.HttpCookie; -import java.net.HttpURLConnection; -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.hippo.ehviewer.util.Log; - -import android.content.Context; -import android.content.SharedPreferences; - -public class PrefCookieHelper implements CookieStore { - private static final String TAG = "PrefCookieHelper"; - private final String PREF_NAME = "cookies"; - - private final SharedPreferences cookiePref; - private Map cookies; - - public PrefCookieHelper(Context context) { - cookiePref = context.getSharedPreferences(PREF_NAME, 0); - - cookies = new HashMap(); - Map all = cookiePref.getAll(); - for (Entry item : all.entrySet()) { - Object value = item.getValue(); - if (value instanceof String) - cookies.put(item.getKey(), (String)value); - } - } - - @Override - public synchronized void add(URI uri, HttpCookie cookie) { - uri.getHost(); - } - - @Override - public synchronized List get(URI uri) { - // TODO Auto-generated method stub - return null; - } - - @Override - public synchronized List getCookies() { - // TODO Auto-generated method stub - return null; - } - - @Override - public synchronized List getURIs() { - // TODO Auto-generated method stub - return null; - } - - @Override - public synchronized boolean remove(URI uri, HttpCookie cookie) { - // TODO Auto-generated method stub - return false; - } - - @Override - public synchronized boolean removeAll() { - // TODO Auto-generated method stub - return false; - } -} diff --git a/src/com/hippo/ehviewer/network/ShapreCookieStore.java b/src/com/hippo/ehviewer/network/ShapreCookieStore.java deleted file mode 100644 index 9d4cee889..000000000 --- a/src/com/hippo/ehviewer/network/ShapreCookieStore.java +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2014 Hippo Seven - * - * 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.hippo.ehviewer.network; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OptionalDataException; -import java.net.CookieStore; -import java.net.HttpCookie; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.hippo.ehviewer.util.Util; - -import android.content.Context; -import android.content.SharedPreferences; - -public class ShapreCookieStore implements CookieStore { - //private static final String TAG = "ShapreCookieStore"; - private final CookieDataSource datasource; - private final Map> map; - - public ShapreCookieStore(Context context) { - datasource = new CookieDataSource(context); - map = datasource.getAll(); - } - - public synchronized void add(URI uri, HttpCookie cookie) { - if (cookie == null) { - throw new NullPointerException("cookie == null"); - } - - uri = cookiesUri(uri); - List cookies = map.get(uri); - if (cookies == null) { - cookies = new ArrayList(); - map.put(uri, cookies); - } else { - cookies.remove(cookie); - } - cookies.add(cookie); - - // For sql - if (cookies != null) { - datasource.add(uri.getHost(), cookie); - } - } - - private URI cookiesUri(URI uri) { - if (uri == null) { - return null; - } - try { - return new URI("http", uri.getHost(), null, null); - } catch (URISyntaxException e) { - return uri; // probably a URI with no host - } - } - - public synchronized List get(URI uri) {/* - if (uri == null) { - throw new NullPointerException("uri == null"); - } - - List result = new ArrayList(); - - // get cookies associated with given URI. If none, returns an empty list - List cookiesForUri = map.get(uri); - if (cookiesForUri != null) { - for (Iterator i = cookiesForUri.iterator(); i.hasNext(); ) { - HttpCookie cookie = i.next(); - if (cookie.hasExpired()) { - i.remove(); // remove expired cookies - // For sql - datasource.remove(uri.getHost(), cookie); - } else { - result.add(cookie); - } - } - } - - // get all cookies that domain matches the URI - for (Map.Entry> entry : map.entrySet()) { - if (uri.equals(entry.getKey())) { - continue; // skip the given URI; we've already handled it - } - - List entryCookies = entry.getValue(); - for (Iterator i = entryCookies.iterator(); i.hasNext(); ) { - HttpCookie cookie = i.next(); - if (!HttpCookie.domainMatches(cookie.getDomain(), uri.getHost())) { - continue; - } - if (cookie.hasExpired()) { - i.remove(); // remove expired cookies - // For sql - datasource.remove(uri.getHost(), cookie); - } else if (!result.contains(cookie)) { - result.add(cookie); - } - } - } - return Collections.unmodifiableList(result);*/ - - - List result = new ArrayList(); - for (URI uri1 : map.keySet()) { - List list = map.get(uri1); - for (Iterator i = list.iterator(); i.hasNext(); ) { - HttpCookie cookie = i.next(); - if (cookie.hasExpired()) { - i.remove(); // remove expired cookies - // For sql - datasource.remove(uri1.getHost(), cookie); - } else if (!result.contains(cookie)) { - result.add(cookie); - } - } - } - return Collections.unmodifiableList(result); - } - - public synchronized List getCookies() { - List result = new ArrayList(); - for (URI uri : map.keySet()) { - List list = map.get(uri); - for (Iterator i = list.iterator(); i.hasNext(); ) { - HttpCookie cookie = i.next(); - if (cookie.hasExpired()) { - i.remove(); // remove expired cookies - // For sql - datasource.remove(uri.getHost(), cookie); - } else if (!result.contains(cookie)) { - result.add(cookie); - } - } - } - return Collections.unmodifiableList(result); - } - - public synchronized List getURIs() { - List result = new ArrayList(map.keySet()); - result.remove(null); // sigh - return Collections.unmodifiableList(result); - } - - public synchronized boolean remove(URI uri, HttpCookie cookie) { - if (cookie == null) { - throw new NullPointerException("cookie == null"); - } - - // For sql - datasource.remove(uri.getHost(), cookie); - - List cookies = map.get(cookiesUri(uri)); - if (cookies != null) { - return cookies.remove(cookie); - } else { - return false; - } - } - - public synchronized boolean removeAll() { - boolean result = !map.isEmpty(); - map.clear(); - - // For sql - datasource.removeAll(); - - return result; - } - - private class CookieDataSource { - - private static final String COOKIE_PREFS = "cookie"; - private static final String COOKIE_URI_LIST = "cookie_uri_list"; - private static final String COOKIE_URI_PREFIX = "uri_"; - private static final String COOKIE_NAME_PREFIX = "name_"; - private final SharedPreferences cookiePrefs; - private final Map> data; - - public CookieDataSource(Context context) { - cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); - data = new HashMap>(); - } - - public Map> getAll() { - Map> map = new HashMap>(); - String rawUris = cookiePrefs.getString(COOKIE_URI_LIST, null); - if (rawUris == null) - return map; - String[] strUris = decodeStrings(rawUris); - - for (String strUri : strUris) { - URI uri = null; - try { - uri = new URI("http", strUri, null, null); - } catch (URISyntaxException e) {continue;} - - // Add to map - data.put(strUri, new HashSet()); - String rawNames = cookiePrefs.getString(COOKIE_URI_PREFIX + strUri, null); - if (rawNames == null) - continue; - String[] names = decodeStrings(rawNames); - List cookies = new ArrayList(); - for (String name : names) { - String strCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + strUri + name, null); - if (strCookie == null) - continue; - - // Add to map - data.get(strUri).add(name); - cookies.add(decodeCookie(strCookie)); - } - map.put(uri, cookies); - } - return map; - } - - - public void add(String uri, HttpCookie cookie) { - Set names = data.get(uri); - if (names == null) { - names = new HashSet(); - data.put(uri, names); - putStrings(COOKIE_URI_LIST, data.keySet()); - } - - if (!names.contains(cookie.getName())) { - names.add(cookie.getName()); - putStrings(COOKIE_URI_PREFIX + uri, names); - } - - cookiePrefs.edit().putString(COOKIE_NAME_PREFIX - + uri + cookie.getName(), - encodeCookie(cookie)) - .apply(); - } - - public void remove(String uri, HttpCookie cookie) { - cookiePrefs.edit().remove(COOKIE_NAME_PREFIX - + uri + cookie.getName()) - .apply(); - - Set names = data.get(uri); - names.remove(cookie.getName()); - if (names.size() != 0) - putStrings(COOKIE_URI_PREFIX + uri, names); - else { - cookiePrefs.edit().remove(COOKIE_URI_PREFIX + uri) - .apply(); - data.remove(uri); - putStrings(COOKIE_URI_LIST, data.keySet()); - } - } - - public void removeAll() { - cookiePrefs.edit().clear().apply(); - } - - public void putStrings(String key, Set values) { - StringBuffer sb = new StringBuffer(); - for (String value : values) { - sb.append(value).append('\n'); - } - int length = sb.length(); - sb.delete(length - 1, length); - cookiePrefs.edit() - .putString(key, Util.byteArrayToHexString( - sb.toString().getBytes())).apply(); - } - - public String[] decodeStrings(String rawStrings) { - return new String(Util.hexStringToByteArray(rawStrings)).split("\n"); - } - - protected String encodeCookie(HttpCookie cookie) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - try { - ObjectOutputStream outputStream = new ObjectOutputStream(os); - writeObject(cookie, outputStream); - } catch (Exception e) { - return null; - } finally { - try { - os.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return Util.byteArrayToHexString(os.toByteArray()); - } - - protected HttpCookie decodeCookie(String cookieStr) { - byte[] bytes = Util.hexStringToByteArray(cookieStr); - ByteArrayInputStream is = new ByteArrayInputStream(bytes); - HttpCookie cookie = null; - try { - ObjectInputStream ois = new ObjectInputStream(is); - cookie = readObject(ois); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - is.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return cookie; - } - } - - - public static void writeObject(HttpCookie cookie, ObjectOutputStream out) throws IOException { - out.writeObject(cookie.getName()); - out.writeObject(cookie.getValue()); - out.writeObject(cookie.getComment()); - out.writeObject(cookie.getCommentURL()); - out.writeObject((Boolean)cookie.getDiscard()); - out.writeObject(cookie.getDomain()); - out.writeObject((Long)cookie.getMaxAge()); - out.writeObject(cookie.getPath()); - out.writeObject(cookie.getPortlist()); - out.writeObject((Boolean)cookie.getSecure()); - out.writeObject((Integer)cookie.getVersion()); - } - - public static HttpCookie readObject(ObjectInputStream in) { - HttpCookie clientCookie = null; - try { - String name = (String)in.readObject(); - String value = (String)in.readObject(); - clientCookie = new HttpCookie(name, value); - clientCookie.setComment((String)in.readObject()); - clientCookie.setCommentURL((String)in.readObject()); - clientCookie.setDiscard((Boolean)in.readObject()); - clientCookie.setDomain((String)in.readObject()); - clientCookie.setMaxAge((Long)in.readObject()); - clientCookie.setPath((String)in.readObject()); - clientCookie.setPortlist((String)in.readObject()); - clientCookie.setSecure((Boolean)in.readObject()); - clientCookie.setVersion((Integer)in.readObject()); - } catch (OptionalDataException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - return clientCookie; - } -} diff --git a/src/com/hippo/ehviewer/ui/AbstractFragmentActivity.java b/src/com/hippo/ehviewer/ui/AbstractFragmentActivity.java index 0bc453b22..5ad7ea3c1 100644 --- a/src/com/hippo/ehviewer/ui/AbstractFragmentActivity.java +++ b/src/com/hippo/ehviewer/ui/AbstractFragmentActivity.java @@ -20,6 +20,7 @@ import android.os.Bundle; import android.support.v4.app.FragmentActivity; import com.google.analytics.tracking.android.EasyTracker; +import com.hippo.ehviewer.cache.ImageCache; import com.hippo.ehviewer.util.Config; public abstract class AbstractFragmentActivity extends FragmentActivity { @@ -53,5 +54,7 @@ public abstract class AbstractFragmentActivity extends FragmentActivity { super.onStop(); if (Config.getAllowAnalyics()) EasyTracker.getInstance(this).activityStop(this); + + ImageCache.getInstance(this).flush(); } } diff --git a/src/com/hippo/ehviewer/ui/AbstractGalleryActivity.java b/src/com/hippo/ehviewer/ui/AbstractGalleryActivity.java index 6f0ae62f1..a791a8d84 100644 --- a/src/com/hippo/ehviewer/ui/AbstractGalleryActivity.java +++ b/src/com/hippo/ehviewer/ui/AbstractGalleryActivity.java @@ -20,14 +20,12 @@ import java.util.ArrayList; import java.util.List; import com.hippo.ehviewer.AppContext; -import com.hippo.ehviewer.ImageGeterManager; +import com.hippo.ehviewer.ImageLoader; import com.hippo.ehviewer.R; +import com.hippo.ehviewer.cache.ImageCache; import com.hippo.ehviewer.data.GalleryInfo; import com.hippo.ehviewer.data.GalleryPopular; import com.hippo.ehviewer.ehclient.EhClient; -import com.hippo.ehviewer.util.Cache; -import com.hippo.ehviewer.util.Config; -import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.util.Ui; import com.hippo.ehviewer.widget.FswView; import com.hippo.ehviewer.widget.HfListView; @@ -35,7 +33,6 @@ import com.hippo.ehviewer.widget.LoadImageView; import com.hippo.ehviewer.widget.OnFitSystemWindowsListener; import com.hippo.ehviewer.widget.SuperToast; -import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; @@ -46,8 +43,6 @@ import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ImageView; -import android.widget.ImageView.ScaleType; -import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RatingBar; @@ -67,7 +62,7 @@ public abstract class AbstractGalleryActivity extends AbstractSlidingActivity protected AppContext mAppContext; protected EhClient mClient; - protected ImageGeterManager mImageGeterManager; + private ImageLoader mImageLoader; private List mGiList; private GalleryAdapter mGalleryAdapter; @@ -273,7 +268,7 @@ public abstract class AbstractGalleryActivity extends AbstractSlidingActivity mAppContext = (AppContext)getApplication(); mClient = mAppContext.getEhClient(); - mImageGeterManager = mAppContext.getImageGeterManager(); + mImageLoader = ImageLoader.getInstance(this); mGiList = new ArrayList(); @@ -440,20 +435,10 @@ public abstract class AbstractGalleryActivity extends AbstractSlidingActivity final LoadImageView thumb = (LoadImageView)convertView.findViewById(R.id.cover); if (!String.valueOf(gi.gid).equals(thumb.getKey())) { - Bitmap bmp = null; - if (Cache.memoryCache != null && - (bmp = Cache.memoryCache.get(String.valueOf(gi.gid))) != null) { - thumb.setLoadInfo(gi.thumb, String.valueOf(gi.gid)); - thumb.setImageBitmap(bmp); - thumb.setState(LoadImageView.LOADED); - } else { - thumb.setImageDrawable(null); - thumb.setLoadInfo(gi.thumb, String.valueOf(gi.gid)); - thumb.setState(LoadImageView.NONE); - mImageGeterManager.add(gi.thumb, String.valueOf(gi.gid), - ImageGeterManager.DISK_CACHE | ImageGeterManager.DOWNLOAD, - new LoadImageView.SimpleImageGetListener(thumb)); - } + thumb.setImageDrawable(null); + thumb.setLoadInfo(gi.thumb, String.valueOf(gi.gid)); + mImageLoader.add(gi.thumb, String.valueOf(gi.gid), + new LoadImageView.SimpleImageGetListener(thumb)); } // Set manga name TextView name = (TextView) convertView.findViewById(R.id.name); @@ -510,7 +495,16 @@ public abstract class AbstractGalleryActivity extends AbstractSlidingActivity } } @Override - public void onScrollStateChanged(AbsListView view, int scrollState) {} + public void onScrollStateChanged(AbsListView view, int scrollState) { + switch (scrollState) { + case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: + ImageCache.getInstance(mAppContext).setPauseDiskCache(true); + break; + case AbsListView.OnScrollListener.SCROLL_STATE_IDLE: + ImageCache.getInstance(mAppContext).setPauseDiskCache(false); + break; + } + } } private void setListPosition(int position) { diff --git a/src/com/hippo/ehviewer/ui/AbstractSlidingActivity.java b/src/com/hippo/ehviewer/ui/AbstractSlidingActivity.java index 99ce9c69a..8ad06a9b1 100644 --- a/src/com/hippo/ehviewer/ui/AbstractSlidingActivity.java +++ b/src/com/hippo/ehviewer/ui/AbstractSlidingActivity.java @@ -19,6 +19,7 @@ package com.hippo.ehviewer.ui; import android.os.Bundle; import com.google.analytics.tracking.android.EasyTracker; +import com.hippo.ehviewer.cache.ImageCache; import com.hippo.ehviewer.util.Config; import com.jeremyfeinstein.slidingmenu.lib.app.SlidingActivity; @@ -53,5 +54,7 @@ public class AbstractSlidingActivity extends SlidingActivity { super.onStop(); if (Config.getAllowAnalyics()) EasyTracker.getInstance(this).activityStop(this); + + ImageCache.getInstance(this).flush(); } } diff --git a/src/com/hippo/ehviewer/ui/DetailSectionFragment.java b/src/com/hippo/ehviewer/ui/DetailSectionFragment.java index de7ac67ce..5139127e0 100644 --- a/src/com/hippo/ehviewer/ui/DetailSectionFragment.java +++ b/src/com/hippo/ehviewer/ui/DetailSectionFragment.java @@ -16,7 +16,6 @@ package com.hippo.ehviewer.ui; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.AbstractMap.SimpleEntry; @@ -24,21 +23,19 @@ import java.util.List; import java.util.Map.Entry; import com.hippo.ehviewer.AppContext; -import com.hippo.ehviewer.ImageGeterManager; +import com.hippo.ehviewer.ImageLoader; import com.hippo.ehviewer.R; import com.hippo.ehviewer.data.Comment; import com.hippo.ehviewer.data.Data; import com.hippo.ehviewer.data.GalleryDetail; import com.hippo.ehviewer.data.GalleryInfo; +import com.hippo.ehviewer.data.NormalPreviewList; import com.hippo.ehviewer.data.PreviewList; import com.hippo.ehviewer.ehclient.DetailParser; import com.hippo.ehviewer.ehclient.EhClient; -import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; -import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.util.Theme; import com.hippo.ehviewer.util.Ui; -import com.hippo.ehviewer.util.Util; import com.hippo.ehviewer.widget.AlertButton; import com.hippo.ehviewer.widget.AutoWrapLayout; import com.hippo.ehviewer.widget.ButtonsDialogBuilder; @@ -53,15 +50,10 @@ import com.hippo.ehviewer.widget.SuperToast; import android.app.Activity; import android.app.AlertDialog; -import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Color; import android.graphics.Path; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.shapes.PathShape; @@ -86,7 +78,7 @@ import android.widget.TextView; import android.widget.ViewSwitcher.ViewFactory; public class DetailSectionFragment extends Fragment - implements View.OnClickListener { + implements View.OnClickListener, PreviewList.PreviewHolder { private static final String TAG = "DetailSectionFragment"; private AppContext mAppContext; @@ -140,7 +132,6 @@ public class DetailSectionFragment extends Fragment } ShapeDrawable d = new ShapeDrawable(new PathShape(path, 50, 100)); d.getPaint().setColor(color); - //d.setBounds(0, 0, Ui.dp2pix(24), Ui.dp2pix(48)); return d; } @@ -154,10 +145,20 @@ public class DetailSectionFragment extends Fragment sld.addState(new int[]{android.R.attr.state_enabled, android.R.attr.state_focused}, dark); sld.addState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}, dark); sld.addState(new int[]{}, normal); - //sld.setBounds(0, 0, Ui.dp2pix(24), Ui.dp2pix(48)); return sld; } + @Override + public int getCurPreviewPage() { + return mCurPage; + } + + @Override + public void onGetPreviewImageFailure() { + mWaitPreviewList.setVisibility(View.GONE); + mPreviewRefreshButton.setVisibility(View.VISIBLE); + } + @SuppressWarnings("deprecation") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -168,12 +169,7 @@ public class DetailSectionFragment extends Fragment mData = mAppContext.getData(); GalleryInfo galleryInfo = mActivity.getGalleryInfo(); - boolean getFromCache = true; - mActivity.mGalleryDetail = Cache.mdCache.get(String.valueOf(galleryInfo.gid)); - if (mActivity.mGalleryDetail == null) { - getFromCache = false; - mActivity.mGalleryDetail = new GalleryDetail(galleryInfo); - } + mActivity.mGalleryDetail = new GalleryDetail(galleryInfo); mGalleryDetail = mActivity.mGalleryDetail; mUrl = EhClient.getDetailUrl( mGalleryDetail.gid, mGalleryDetail.token); @@ -257,20 +253,10 @@ public class DetailSectionFragment extends Fragment }); LoadImageView thumb = (LoadImageView)mRootView.findViewById(R.id.detail_cover); - Bitmap bmp = null; - if (Cache.memoryCache != null && - (bmp = Cache.memoryCache.get(String.valueOf(mGalleryDetail.gid))) != null) { - thumb.setLoadInfo(mGalleryDetail.thumb, String.valueOf(mGalleryDetail.gid)); - thumb.setImageBitmap(bmp); - thumb.setState(LoadImageView.LOADED); - } else { - thumb.setImageDrawable(null); - thumb.setLoadInfo(mGalleryDetail.thumb, String.valueOf(mGalleryDetail.gid)); - thumb.setState(LoadImageView.NONE); - mAppContext.getImageGeterManager().add(mGalleryDetail.thumb, String.valueOf(mGalleryDetail.gid), - ImageGeterManager.DISK_CACHE | ImageGeterManager.DOWNLOAD, - new LoadImageView.SimpleImageGetListener(thumb)); - } + thumb.setImageDrawable(null); + thumb.setLoadInfo(mGalleryDetail.thumb, String.valueOf(mGalleryDetail.gid)); + ImageLoader.getInstance(mActivity).add(mGalleryDetail.thumb, String.valueOf(mGalleryDetail.gid), + new LoadImageView.SimpleImageGetListener(thumb).setTransitabled(false)); TextView title = (TextView)mRootView.findViewById(R.id.detail_title); title.setText(mGalleryDetail.title); @@ -296,103 +282,41 @@ public class DetailSectionFragment extends Fragment mReadButton.setEnabled(false); mRateButton.setEnabled(false); - // get from cache - if (getFromCache) - layout(mGalleryDetail); - else - mClient.getGDetail(mUrl, mGalleryDetail, new GDetailGetListener()); + mClient.getGDetail(mUrl, mGalleryDetail, new GDetailGetListener()); return mRootView; } - private void addPageItem(int page) { - if (mActivity.isFinishing()) - return; - - if (page != mCurPage) - return; - - mWaitPreviewList.setVisibility(View.GONE); - mPreviewRefreshButton.setVisibility(View.GONE); - - PreviewList pageList = mGalleryDetail.previewLists[page]; - if (pageList == null) { - Log.d(TAG, "WTF, I may check mangaDetail.pageLists[page] is not null"); - new SuperToast(mActivity).setIcon(R.drawable.ic_warning) - .setMessage("WTF, I may check mangaDetail.pageLists[page] is not null") - .show(); - return; - } - int index = page * mGalleryDetail.previewPerPage + 1; - int rowIndex = 0; - for (PreviewList.Row row : pageList.rowArray) { - for (PreviewList.Row.Item item : row.itemArray) { - TextViewWithUrl tvu = new TextViewWithUrl(mActivity, - item.url); - tvu.setGravity(Gravity.CENTER); - tvu.setText(String.valueOf(index)); - final int index1 = index; - tvu.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - // Add to read in Data - mData.addRead(mGalleryDetail); - - Intent intent = new Intent(mActivity, - MangaActivity.class); - intent.putExtra("url", ((TextViewWithUrl) v).url); - intent.putExtra("gid", mGalleryDetail.gid); - intent.putExtra("title", mGalleryDetail.title); - intent.putExtra("firstPage", index1 - 1); - intent.putExtra("pageSum", mGalleryDetail.pages); - startActivity(intent); - } - }); - // Set white drawable for temp - ColorDrawable white = new ColorDrawable(Color.TRANSPARENT); - white.setBounds(0, 0, item.width, item.height); - tvu.setCompoundDrawables(null, white, null, null); - - AutoWrapLayout.LayoutParams lp = new AutoWrapLayout.LayoutParams(); - lp.leftMargin = Ui.dp2pix(8); - lp.topMargin = Ui.dp2pix(8); - lp.rightMargin = Ui.dp2pix(8); - lp.bottomMargin = Ui.dp2pix(8); - - mPreviewListLayout.addView(tvu, lp); - index++; - } - // Download pic - EhClient.getImage(row.imageUrl, mGalleryDetail.gid + "-preview-" - + mCurPage + "-" + rowIndex, Util.getResourcesType(row.imageUrl), Cache.memoryCache, - Cache.diskCache, new int[]{page, rowIndex}, new PageImageGetListener()); - rowIndex ++; - } - } - private void refreshPageList() { mPreviewListLayout.removeAllViews(); - mWaitPreviewList.setVisibility(View.VISIBLE); - mPreviewRefreshButton.setVisibility(View.GONE); - mPreviewNumText.setText(String.format("%d / %d", mCurPage+1, mGalleryDetail.previewSum)); - + PreviewList pageList = mGalleryDetail.previewLists[mCurPage]; - + if (pageList == null) { + // Update layout + mWaitPreviewList.setVisibility(View.VISIBLE); + mPreviewRefreshButton.setVisibility(View.GONE); + mUrl = EhClient.getDetailUrl( mGalleryDetail.gid, mGalleryDetail.token, mCurPage); - mClient.getPageList(mUrl, mCurPage, - new EhClient.OnGetPageListListener() { + mClient.getPreviewList(mUrl, mCurPage, + new EhClient.OnGetPreviewListListener() { @Override - public void onSuccess(Object checkFlag, PreviewList pageList) { + public void onSuccess(Object checkFlag, NormalPreviewList pageList) { if (mActivity.isFinishing()) return; + mWaitPreviewList.setVisibility(View.GONE); + mPreviewRefreshButton.setVisibility(View.GONE); + int page = (Integer)checkFlag; mGalleryDetail.previewLists[page] = pageList; - addPageItem(page); + mGalleryDetail.previewLists[page].setData(DetailSectionFragment.this, mActivity, mGalleryDetail, page); + mGalleryDetail.previewLists[page].addPreview(mPreviewListLayout); + + mShowPreview = true; } @@ -412,7 +336,11 @@ public class DetailSectionFragment extends Fragment } }); } else { - addPageItem(mCurPage); + // Update layout + mWaitPreviewList.setVisibility(View.GONE); + mPreviewRefreshButton.setVisibility(View.GONE); + + mGalleryDetail.previewLists[mCurPage].addPreview(mPreviewListLayout); mShowPreview = true; } } @@ -642,7 +570,8 @@ public class DetailSectionFragment extends Fragment } mCurPage = 0; - addPageItem(0); + mGalleryDetail.previewLists[0].setData(this, mActivity, mGalleryDetail, 0); + mGalleryDetail.previewLists[0].addPreview(mPreviewListLayout); } else new SuperToast(mActivity) .setMessage(R.string.detail_preview_error) @@ -797,20 +726,10 @@ public class DetailSectionFragment extends Fragment return mGalleryDetail.comments; } - private class TextViewWithUrl extends TextView { - private String url; - - public TextViewWithUrl(Context context, String url) { - super(context); - this.url = url; - } - } - private class GDetailGetListener implements EhClient.OnGetGDetailListener { @Override public void onSuccess(GalleryDetail md) { - Cache.mdCache.put(String.valueOf(mGalleryDetail.gid), md); layout(md); } @@ -823,62 +742,6 @@ public class DetailSectionFragment extends Fragment new SuperToast(mActivity).setIcon(R.drawable.ic_warning).setMessage(eMsg).show(); } } - private class PageImageGetListener implements EhClient.OnGetImageListener { - @Override - public void onSuccess(Object checkFlag, Object res) { - if (res instanceof Bitmap && checkFlag instanceof int[]) { - int[] indexs = (int[])checkFlag; - addPageImage(indexs[0], indexs[1], (Bitmap) res); - } else { - Log.e(TAG, "WTF? PageImageGetListener is error !"); - mWaitPreviewList.setVisibility(View.GONE); - mPreviewRefreshButton.setVisibility(View.VISIBLE); - } - } - @Override - public void onFailure(int errorMessageId) { - mWaitPreviewList.setVisibility(View.GONE); - mPreviewRefreshButton.setVisibility(View.VISIBLE); - } - - private void addPageImage(int page, int rowIndex, Bitmap bitmap) { - if (mActivity.isFinishing()) - return; - - if (page != mCurPage) - return; - PreviewList pageList = mGalleryDetail.previewLists[page]; - if (pageList == null) { - Log.d(TAG, "WTF, I may check mangaDetail.pageLists[page] is not null"); - return; - } - - int maxWidth = bitmap.getWidth(); - int maxHeight = bitmap.getHeight(); - - PreviewList.Row row = pageList.rowArray.get(rowIndex); - ArrayList items = row.itemArray; - - int startIndex = row.startIndex; - int endIndex = startIndex + items.size(); - for(int i = startIndex ; i < endIndex; i++) { - PreviewList.Row.Item item = items.get(i - startIndex); - - if (item.xOffset + item.width > maxWidth) - item.width = maxWidth - item.xOffset; - if (item.yOffset + item.height > maxHeight) - item.height = maxHeight - item.yOffset; - - BitmapDrawable bitmapDrawable = new BitmapDrawable( - getResources(), Bitmap.createBitmap(bitmap, - item.xOffset, item.yOffset, item.width, item.height)); - bitmapDrawable.setBounds(0, 0, item.width, item.height); - - TextViewWithUrl tvu = (TextViewWithUrl)mPreviewListLayout.getChildAt(i); - tvu.setCompoundDrawables(null, bitmapDrawable, null, null); - } - } - } private class SimpleVote implements View.OnClickListener { diff --git a/src/com/hippo/ehviewer/ui/DownloadActivity.java b/src/com/hippo/ehviewer/ui/DownloadActivity.java index a8d6adcb4..b8a2fb711 100644 --- a/src/com/hippo/ehviewer/ui/DownloadActivity.java +++ b/src/com/hippo/ehviewer/ui/DownloadActivity.java @@ -21,11 +21,10 @@ import java.io.IOException; import java.util.List; import com.hippo.ehviewer.AppContext; -import com.hippo.ehviewer.ImageGeterManager; +import com.hippo.ehviewer.ImageLoader; import com.hippo.ehviewer.R; import com.hippo.ehviewer.service.DownloadService; import com.hippo.ehviewer.service.DownloadServiceConnection; -import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Download; import com.hippo.ehviewer.util.Ui; @@ -63,7 +62,7 @@ public class DownloadActivity extends AbstractActivity { private DownloadServiceConnection mServiceConn = new DownloadServiceConnection(); private AppContext mAppContext; - private ImageGeterManager mImageGeterManager; + private ImageLoader mImageLoader; private List mDownloadInfos; private DlAdapter mDlAdapter; @@ -155,20 +154,10 @@ public class DownloadActivity extends AbstractActivity { LoadImageView thumb = (LoadImageView)view .findViewById(R.id.thumb); - Bitmap bmp = null; - if (Cache.memoryCache != null && - (bmp = Cache.memoryCache.get(di.gid)) != null) { - thumb.setLoadInfo(di.thumb, di.gid); - thumb.setImageBitmap(bmp); - thumb.setState(LoadImageView.LOADED); - } else { - thumb.setImageDrawable(null); - thumb.setLoadInfo(di.thumb, di.gid); - thumb.setState(LoadImageView.NONE); - mImageGeterManager.add(di.thumb, di.gid, - ImageGeterManager.DISK_CACHE | ImageGeterManager.DOWNLOAD, - new LoadImageView.SimpleImageGetListener(thumb)); - } + thumb.setImageDrawable(null); + thumb.setLoadInfo(di.thumb, di.gid); + mImageLoader.add(di.thumb, di.gid, + new LoadImageView.SimpleImageGetListener(thumb)); TextView title = (TextView)view.findViewById(R.id.title); title.setText(di.title); @@ -221,20 +210,10 @@ public class DownloadActivity extends AbstractActivity { LoadImageView thumb = (LoadImageView)view .findViewById(R.id.thumb); - Bitmap bmp = null; - if (Cache.memoryCache != null && - (bmp = Cache.memoryCache.get(di.gid)) != null) { - thumb.setLoadInfo(di.thumb, di.gid); - thumb.setImageBitmap(bmp); - thumb.setState(LoadImageView.LOADED); - } else { - thumb.setImageDrawable(null); - thumb.setLoadInfo(di.thumb, di.gid); - thumb.setState(LoadImageView.NONE); - mImageGeterManager.add(di.thumb, di.gid, - ImageGeterManager.DISK_CACHE | ImageGeterManager.DOWNLOAD, - new LoadImageView.SimpleImageGetListener(thumb)); - } + thumb.setImageDrawable(null); + thumb.setLoadInfo(di.thumb, di.gid); + mImageLoader.add(di.thumb, di.gid, + new LoadImageView.SimpleImageGetListener(thumb)); TextView title = (TextView)view.findViewById(R.id.title); title.setText(di.title); @@ -375,7 +354,7 @@ public class DownloadActivity extends AbstractActivity { setContentView(R.layout.download); mAppContext = (AppContext)getApplication(); - mImageGeterManager = mAppContext.getImageGeterManager(); + mImageLoader = ImageLoader.getInstance(this); Ui.translucent(this); diff --git a/src/com/hippo/ehviewer/ui/FavouriteActivity.java b/src/com/hippo/ehviewer/ui/FavouriteActivity.java index d43ce3f28..c6a65aa11 100644 --- a/src/com/hippo/ehviewer/ui/FavouriteActivity.java +++ b/src/com/hippo/ehviewer/ui/FavouriteActivity.java @@ -138,7 +138,6 @@ public class FavouriteActivity extends AbstractGalleryActivity mAppContext = (AppContext)getApplication(); mData = mAppContext.getData(); mResources =getResources(); - mImageGeterManager = mAppContext.getImageGeterManager(); mClient = mAppContext.getEhClient(); final ActionBar actionBar = getActionBar(); diff --git a/src/com/hippo/ehviewer/ui/SettingsActivity.java b/src/com/hippo/ehviewer/ui/SettingsActivity.java index 924e73c04..1f6be68d5 100644 --- a/src/com/hippo/ehviewer/ui/SettingsActivity.java +++ b/src/com/hippo/ehviewer/ui/SettingsActivity.java @@ -24,10 +24,8 @@ import java.util.LinkedList; import java.util.List; import com.hippo.ehviewer.AppContext; -import com.hippo.ehviewer.DiskCache; import com.hippo.ehviewer.R; import com.hippo.ehviewer.UpdateHelper; -import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Favorite; import com.hippo.ehviewer.util.Theme; @@ -351,6 +349,7 @@ public class SettingsActivity extends AbstractPreferenceActivity { } private void updateClearCacheSummary() { + /* if (Cache.diskCache != null) { mClearCache.setSummary(String.format( getString(R.string.clear_cache_summary_on), @@ -362,12 +361,15 @@ public class SettingsActivity extends AbstractPreferenceActivity { .setSummary(getString(R.string.clear_cache_summary_off)); mClearCache.setEnabled(false); } + */ } @Override public boolean onPreferenceChange(Preference preference, Object objValue) { final String key = preference.getKey(); if (KEY_CACHE_SIZE.equals(key)) { + /* + long cacheSize = 0; try { cacheSize = Integer.parseInt((String) objValue) * 1024 * 1024; @@ -393,7 +395,7 @@ public class SettingsActivity extends AbstractPreferenceActivity { } else Cache.diskCache.setMaxSize(cacheSize); updateClearCacheSummary(); - + */ } else if (KEY_MEDIA_SCAN.equals(key)) { boolean value = (Boolean)objValue; File nomedia = new File(Config.getDownloadPath(), ".nomedia"); @@ -413,9 +415,10 @@ public class SettingsActivity extends AbstractPreferenceActivity { public boolean onPreferenceClick(Preference preference) { final String key = preference.getKey(); if (KEY_CLEAR_CACHE.equals(key)) { + /* Cache.diskCache.clear(); updateClearCacheSummary(); - + */ } else if (KEY_DOWNLOAD_PATH.equals(key)) { View view = LayoutInflater.from(mActivity) .inflate(R.layout.dir_selection, null); diff --git a/src/com/hippo/ehviewer/util/Cache.java b/src/com/hippo/ehviewer/util/Cache.java deleted file mode 100644 index 87fbcf795..000000000 --- a/src/com/hippo/ehviewer/util/Cache.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2014 Hippo Seven - * - * 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.hippo.ehviewer.util; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Bitmap; -import android.os.Build; -import android.os.Environment; -import android.support.v4.util.LruCache; - -import com.hippo.ehviewer.data.GalleryDetail; -import com.hippo.ehviewer.DiskCache; - -public class Cache { - private static final String TAG = "Cache"; - - private static Context mContext; - - public static final String cpCachePath = "/EhViewer/cache/cover"; - public static DiskCache diskCache = null; - public static LruCache memoryCache = null; - public static LruCache mdCache = null; - - private static final int MD_CACHE_SIZE = 5; - - private static boolean mInit = false; - - /** - * Init Cache - * - * @param context Application context - */ - public static void init(Context context) { - if (mInit) - return; - mInit = true; - - mContext = context; - - if (hasSdCard()) { - try { - int cpCacheSize = Config.getCoverDiskCacheSize() * 1024 * 1024; - if (cpCacheSize <= 0) - diskCache = null; - else - diskCache = new DiskCache(mContext, cpCachePath, cpCacheSize); - } catch (Exception e) { - e.printStackTrace(); - } - } - - //final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); - final int cacheSize = 8 * 1024 * 1024; // 8MB, can store 80 thumb - memoryCache = new LruCache(cacheSize) { - @SuppressLint("NewApi") - @Override - protected int sizeOf(String key, Bitmap bitmap) { - if (Build.VERSION.SDK_INT < 19) - return bitmap.getByteCount(); - else - return bitmap.getAllocationByteCount(); - } - }; - - mdCache = new LruCache(MD_CACHE_SIZE) { - @Override - protected int sizeOf(String key, GalleryDetail md) { - return 1; - } - }; - } - - /** - * Is init - * @return True if init - */ - public static boolean isInit() { - return mInit; - } - - /** - * Have sd card or not - * @return True if has sd card - */ - public static boolean hasSdCard() { - return Environment.getExternalStorageState().equals( - Environment.MEDIA_MOUNTED); - } -} diff --git a/src/com/hippo/ehviewer/widget/LoadImageView.java b/src/com/hippo/ehviewer/widget/LoadImageView.java index 7b3e4e3df..fbafd3a69 100644 --- a/src/com/hippo/ehviewer/widget/LoadImageView.java +++ b/src/com/hippo/ehviewer/widget/LoadImageView.java @@ -16,8 +16,9 @@ package com.hippo.ehviewer.widget; -import com.hippo.ehviewer.ImageGeterManager; +import com.hippo.ehviewer.ImageLoader; import com.hippo.ehviewer.R; +import com.hippo.ehviewer.util.Log; import com.hippo.ehviewer.util.Ui; import android.content.Context; @@ -33,7 +34,6 @@ import android.view.animation.AlphaAnimation; import android.widget.ImageView; public class LoadImageView extends ImageView { - @SuppressWarnings("unused") private static final String TAG = "LoadImageView"; public static final int NONE = 0x0; @@ -51,8 +51,6 @@ public class LoadImageView extends ImageView { private String mUrl; private String mKey; - private static ImageGeterManager mImageGeterManager; - public LoadImageView(Context context) { super(context); } @@ -80,8 +78,7 @@ public class LoadImageView extends ImageView { public void onClick(View v) { setClickable(false); setImageDrawable(null); - mImageGeterManager.add(mUrl, mKey, - ImageGeterManager.DISK_CACHE | ImageGeterManager.DOWNLOAD, + ImageLoader.getInstance(getContext()).add(mUrl, mKey, new SimpleImageGetListener(LoadImageView.this)); } }); @@ -129,17 +126,19 @@ public class LoadImageView extends ImageView { */ } - public static void setImageGeterManager(ImageGeterManager i) { - mImageGeterManager = i; - } - public static class SimpleImageGetListener - implements ImageGeterManager.OnGetImageListener { - + implements ImageLoader.OnGetImageListener { + private boolean mIsTransitabled = true; private LoadImageView mLiv; public SimpleImageGetListener(LoadImageView liv) { mLiv = liv; + mLiv.setState(LoadImageView.LOADING); + } + + public SimpleImageGetListener setTransitabled(boolean isTransitabled) { + mIsTransitabled = isTransitabled; + return this; } public boolean isVaild(String key) { @@ -148,31 +147,19 @@ public class LoadImageView extends ImageView { } @Override - public boolean onGetImageStart(String key) { - boolean re = isVaild(key) && (mLiv.getState() == LoadImageView.NONE || - mLiv.getState() == LoadImageView.FAIL); - if (re) - mLiv.setState(LoadImageView.LOADING); - return re; - } - @Override - public void onGetImageFail(String key) { + public void onGetImage(String key, Bitmap bmp) { if (isVaild(key) && mLiv.getState() == LoadImageView.LOADING) { - mLiv.setTouchImage(); - mLiv.setOnClick(); - mLiv.setState(LoadImageView.FAIL); - } - } - @Override - public void onGetImageSuccess(String key, Bitmap bmp, int mode) { - if (isVaild(key) && mLiv.getState() == LoadImageView.LOADING) { - if (mode == ImageGeterManager.MEMORY_CACHE - || mode == ImageGeterManager.DISK_CACHE) - mLiv.setImageBitmap(bmp); - else if (mode == ImageGeterManager.DOWNLOAD) { - mLiv.setContextImage(bmp); + if (bmp != null) { + if (mIsTransitabled) + mLiv.setContextImage(bmp); + else + mLiv.setImageBitmap(bmp); + mLiv.setState(LoadImageView.LOADED); + } else { + mLiv.setTouchImage(); + mLiv.setOnClick(); + mLiv.setState(LoadImageView.FAIL); } - mLiv.setState(LoadImageView.LOADED); } } } diff --git a/src/com/jakewharton/disklrucache/DiskLruCache.java b/src/com/jakewharton/disklrucache/DiskLruCache.java deleted file mode 100644 index 4ae961c19..000000000 --- a/src/com/jakewharton/disklrucache/DiskLruCache.java +++ /dev/null @@ -1,968 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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.jakewharton.disklrucache; - -import java.io.BufferedWriter; -import java.io.Closeable; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.hippo.ehviewer.util.Log; - -/** - * A cache that uses a bounded amount of space on a filesystem. Each cache entry - * has a string key and a fixed number of values. Each key must match the regex - * [a-z0-9_-]{1,64}. Values are byte sequences, accessible as - * streams or files. Each value must be between {@code 0} and - * {@code Integer.MAX_VALUE} bytes in length. - * - *

- * The cache stores its data in a directory on the filesystem. This directory - * must be exclusive to the cache; the cache may delete or overwrite files from - * its directory. It is an error for multiple processes to use the same cache - * directory at the same time. - * - *

- * This cache limits the number of bytes that it will store on the filesystem. - * When the number of stored bytes exceeds the limit, the cache will remove - * entries in the background until the limit is satisfied. The limit is not - * strict: the cache may temporarily exceed it while waiting for files to be - * deleted. The limit does not include filesystem overhead or the cache journal - * so space-sensitive applications should set a conservative limit. - * - *

- * Clients call {@link #edit} to create or update the values of an entry. An - * entry may have only one editor at one time; if a value is not available to be - * edited then {@link #edit} will return null. - *

    - *
  • When an entry is being created it is necessary to supply - * a full set of values; the empty value should be used as a placeholder if - * necessary. - *
  • When an entry is being edited, it is not necessary to - * supply data for every value; values default to their previous value. - *
- * Every {@link #edit} call must be matched by a call to {@link Editor#commit} - * or {@link Editor#abort}. Committing is atomic: a read observes the full set - * of values as they were before or after the commit, but never a mix of values. - * - *

- * Clients call {@link #get} to read a snapshot of an entry. The read will - * observe the value at the time that {@link #get} was called. Updates and - * removals after the call do not impact ongoing reads. - * - *

- * This class is tolerant of some I/O errors. If files are missing from the - * filesystem, the corresponding entries will be dropped from the cache. If an - * error occurs while writing a cache value, the edit will fail silently. - * Callers should handle other problems by catching {@code IOException} and - * responding appropriately. - */ -public final class DiskLruCache implements Closeable { - static final String TAG = "DiskLruCache"; - static final String JOURNAL_FILE = "journal"; - static final String JOURNAL_FILE_TEMP = "journal.tmp"; - static final String JOURNAL_FILE_BACKUP = "journal.bkp"; - static final String MAGIC = "libcore.io.DiskLruCache"; - static final String VERSION_1 = "1"; - static final long ANY_SEQUENCE_NUMBER = -1; - static final Pattern LEGAL_KEY_PATTERN = Pattern - .compile("[a-z0-9_-]{1,64}"); - private static final String CLEAN = "CLEAN"; - private static final String DIRTY = "DIRTY"; - private static final String REMOVE = "REMOVE"; - private static final String READ = "READ"; - - /* - * This cache uses a journal file named "journal". A typical journal file - * looks like this: libcore.io.DiskLruCache 1 100 2 - * - * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 DIRTY - * 335c4c6028171cfddfbaae1a9c313c52 CLEAN 335c4c6028171cfddfbaae1a9c313c52 - * 3934 2342 REMOVE 335c4c6028171cfddfbaae1a9c313c52 DIRTY - * 1ab96a171faeeee38496d8b330771a7a CLEAN 1ab96a171faeeee38496d8b330771a7a - * 1600 234 READ 335c4c6028171cfddfbaae1a9c313c52 READ - * 3400330d1dfc7f3f7f4b8d4d803dfcf6 - * - * The first five lines of the journal form its header. They are the - * constant string "libcore.io.DiskLruCache", the disk cache's version, the - * application's version, the value count, and a blank line. - * - * Each of the subsequent lines in the file is a record of the state of a - * cache entry. Each line contains space-separated values: a state, a key, - * and optional state-specific values. o DIRTY lines track that an entry is - * actively being created or updated. Every successful DIRTY action should - * be followed by a CLEAN or REMOVE action. DIRTY lines without a matching - * CLEAN or REMOVE indicate that temporary files may need to be deleted. o - * CLEAN lines track a cache entry that has been successfully published and - * may be read. A publish line is followed by the lengths of each of its - * values. o READ lines track accesses for LRU. o REMOVE lines track entries - * that have been deleted. - * - * The journal file is appended to as cache operations occur. The journal - * may occasionally be compacted by dropping redundant lines. A temporary - * file named "journal.tmp" will be used during compaction; that file should - * be deleted if it exists when the cache is opened. - */ - - private final File directory; - private final File journalFile; - private final File journalFileTmp; - private final File journalFileBackup; - private final int appVersion; - private long maxSize; - private final int valueCount; - private long size = 0; - private Writer journalWriter; - private final LinkedHashMap lruEntries = new LinkedHashMap( - 0, 0.75f, true); - private int redundantOpCount; - - /** - * To differentiate between old and current snapshots, each entry is given a - * sequence number each time an edit is committed. A snapshot is stale if - * its sequence number is not equal to its entry's sequence number. - */ - private long nextSequenceNumber = 0; - - /** This cache uses a single background thread to evict entries. */ - final ThreadPoolExecutor executorService = new ThreadPoolExecutor(0, 1, - 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); - private final Callable cleanupCallable = new Callable() { - public Void call() throws Exception { - synchronized (DiskLruCache.this) { - if (journalWriter == null) { - return null; // Closed. - } - trimToSize(); - if (journalRebuildRequired()) { - rebuildJournal(); - redundantOpCount = 0; - } - } - return null; - } - }; - - private DiskLruCache(File directory, int appVersion, int valueCount, - long maxSize) { - this.directory = directory; - this.appVersion = appVersion; - this.journalFile = new File(directory, JOURNAL_FILE); - this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP); - this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP); - this.valueCount = valueCount; - this.maxSize = maxSize; - } - - /** - * Opens the cache in {@code directory}, creating a cache if none exists - * there. - * - * @param directory - * a writable directory - * @param valueCount - * the number of values per cache entry. Must be positive. - * @param maxSize - * the maximum number of bytes this cache should use to store - * @throws IOException - * if reading or writing the cache directory fails - */ - public static DiskLruCache open(File directory, int appVersion, - int valueCount, long maxSize) throws IOException { - if (maxSize <= 0) { - throw new IllegalArgumentException("maxSize <= 0"); - } - if (valueCount <= 0) { - throw new IllegalArgumentException("valueCount <= 0"); - } - - // If a bkp file exists, use it instead. - File backupFile = new File(directory, JOURNAL_FILE_BACKUP); - if (backupFile.exists()) { - File journalFile = new File(directory, JOURNAL_FILE); - // If journal file also exists just delete backup file. - if (journalFile.exists()) { - backupFile.delete(); - } else { - renameTo(backupFile, journalFile, false); - } - } - - // Prefer to pick up where we left off. - DiskLruCache cache = new DiskLruCache(directory, appVersion, - valueCount, maxSize); - if (cache.journalFile.exists()) { - try { - cache.readJournal(); - cache.processJournal(); - cache.journalWriter = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream( - cache.journalFile, true), Util.US_ASCII)); - return cache; - } catch (IOException journalIsCorrupt) { - System.out.println("DiskLruCache " + directory - + " is corrupt: " + journalIsCorrupt.getMessage() - + ", removing"); - cache.delete(); - } - } - - // Create a new empty cache. - directory.mkdirs(); - cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); - cache.rebuildJournal(); - return cache; - } - - private void readJournal() throws IOException { - StrictLineReader reader = new StrictLineReader(new FileInputStream( - journalFile), Util.US_ASCII); - try { - String magic = reader.readLine(); - String version = reader.readLine(); - String appVersionString = reader.readLine(); - String valueCountString = reader.readLine(); - String blank = reader.readLine(); - if (!MAGIC.equals(magic) || !VERSION_1.equals(version) - || !Integer.toString(appVersion).equals(appVersionString) - || !Integer.toString(valueCount).equals(valueCountString) - || !"".equals(blank)) { - throw new IOException("unexpected journal header: [" + magic - + ", " + version + ", " + valueCountString + ", " - + blank + "]"); - } - - int lineCount = 0; - while (true) { - try { - readJournalLine(reader.readLine()); - lineCount++; - } catch (EOFException endOfJournal) { - break; - } - } - redundantOpCount = lineCount - lruEntries.size(); - } finally { - Util.closeQuietly(reader); - } - } - - private void readJournalLine(String line) throws IOException { - int firstSpace = line.indexOf(' '); - if (firstSpace == -1) { - throw new IOException("unexpected journal line: " + line); - } - - int keyBegin = firstSpace + 1; - int secondSpace = line.indexOf(' ', keyBegin); - final String key; - if (secondSpace == -1) { - key = line.substring(keyBegin); - if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) { - lruEntries.remove(key); - return; - } - } else { - key = line.substring(keyBegin, secondSpace); - } - - Entry entry = lruEntries.get(key); - if (entry == null) { - entry = new Entry(key); - lruEntries.put(key, entry); - } - - if (secondSpace != -1 && firstSpace == CLEAN.length() - && line.startsWith(CLEAN)) { - String[] parts = line.substring(secondSpace + 1).split(" "); - entry.readable = true; - entry.currentEditor = null; - entry.setLengths(parts); - } else if (secondSpace == -1 && firstSpace == DIRTY.length() - && line.startsWith(DIRTY)) { - entry.currentEditor = new Editor(entry); - } else if (secondSpace == -1 && firstSpace == READ.length() - && line.startsWith(READ)) { - // This work was already done by calling lruEntries.get(). - } else { - throw new IOException("unexpected journal line: " + line); - } - } - - /** - * Computes the initial size and collects garbage as a part of opening the - * cache. Dirty entries are assumed to be inconsistent and will be deleted. - */ - private void processJournal() throws IOException { - deleteIfExists(journalFileTmp); - for (Iterator i = lruEntries.values().iterator(); i.hasNext();) { - Entry entry = i.next(); - if (entry.currentEditor == null) { - for (int t = 0; t < valueCount; t++) { - size += entry.lengths[t]; - } - } else { - entry.currentEditor = null; - for (int t = 0; t < valueCount; t++) { - deleteIfExists(entry.getCleanFile(t)); - deleteIfExists(entry.getDirtyFile(t)); - } - i.remove(); - } - } - } - - /** - * Creates a new journal that omits redundant information. This replaces the - * current journal if it exists. - */ - private synchronized void rebuildJournal() throws IOException { - if (journalWriter != null) { - journalWriter.close(); - } - - Writer writer = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(journalFileTmp), Util.US_ASCII)); - try { - writer.write(MAGIC); - writer.write("\n"); - writer.write(VERSION_1); - writer.write("\n"); - writer.write(Integer.toString(appVersion)); - writer.write("\n"); - writer.write(Integer.toString(valueCount)); - writer.write("\n"); - writer.write("\n"); - - for (Entry entry : lruEntries.values()) { - if (entry.currentEditor != null) { - writer.write(DIRTY + ' ' + entry.key + '\n'); - } else { - writer.write(CLEAN + ' ' + entry.key + entry.getLengths() - + '\n'); - } - } - } finally { - writer.close(); - } - - if (journalFile.exists()) { - renameTo(journalFile, journalFileBackup, true); - } - renameTo(journalFileTmp, journalFile, false); - journalFileBackup.delete(); - - journalWriter = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(journalFile, true), Util.US_ASCII)); - } - - private static void deleteIfExists(File file) throws IOException { - if (file.exists() && !file.delete()) { - throw new IOException(); - } - } - - private static void renameTo(File from, File to, boolean deleteDestination) - throws IOException { - if (deleteDestination) { - deleteIfExists(to); - } - if (!from.renameTo(to)) { - throw new IOException(); - } - } - - /** - * Returns a snapshot of the entry named {@code key}, or null if it doesn't - * exist is not currently readable. If a value is returned, it is moved to - * the head of the LRU queue. - */ - public synchronized Snapshot get(String key) throws IOException { - checkNotClosed(); - validateKey(key); - Entry entry = lruEntries.get(key); - if (entry == null) { - return null; - } - - if (!entry.readable) { - return null; - } - - // Open all streams eagerly to guarantee that we see a single published - // snapshot. If we opened streams lazily then the streams could come - // from different edits. - InputStream[] ins = new InputStream[valueCount]; - try { - for (int i = 0; i < valueCount; i++) { - ins[i] = new FileInputStream(entry.getCleanFile(i)); - } - } catch (FileNotFoundException e) { - // A file must have been deleted manually! - for (int i = 0; i < valueCount; i++) { - if (ins[i] != null) { - Util.closeQuietly(ins[i]); - } else { - break; - } - } - return null; - } - - redundantOpCount++; - journalWriter.append(READ + ' ' + key + '\n'); - if (journalRebuildRequired()) { - executorService.submit(cleanupCallable); - } - - return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths); - } - - /** - * Returns an editor for the entry named {@code key}, or null if another - * edit is in progress. - */ - public Editor edit(String key) throws IOException { - return edit(key, ANY_SEQUENCE_NUMBER); - } - - private synchronized Editor edit(String key, long expectedSequenceNumber) - throws IOException { - checkNotClosed(); - validateKey(key); - Entry entry = lruEntries.get(key); - if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER - && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { - return null; // Snapshot is stale. - } - if (entry == null) { - entry = new Entry(key); - lruEntries.put(key, entry); - } else if (entry.currentEditor != null) { - return null; // Another edit is in progress. - } - - Editor editor = new Editor(entry); - entry.currentEditor = editor; - - // Flush the journal before creating files to prevent file leaks. - journalWriter.write(DIRTY + ' ' + key + '\n'); - journalWriter.flush(); - return editor; - } - - /** Returns the directory where this cache stores its data. */ - public File getDirectory() { - return directory; - } - - /** - * Returns the maximum number of bytes that this cache should use to store - * its data. - */ - public synchronized long getMaxSize() { - return maxSize; - } - - /** - * Changes the maximum number of bytes the cache can store and queues a job - * to trim the existing store, if necessary. - */ - public synchronized void setMaxSize(long maxSize) { - if (maxSize <= 0) { - throw new IllegalArgumentException("maxSize <= 0"); - } - this.maxSize = maxSize; - executorService.submit(cleanupCallable); - } - - /** - * Returns the number of bytes currently being used to store the values in - * this cache. This may be greater than the max size if a background - * deletion is pending. - */ - public synchronized long size() { - return size; - } - - private synchronized void completeEdit(Editor editor, boolean success) - throws IOException { - Entry entry = editor.entry; - if (entry.currentEditor != editor) { - // throw new IllegalStateException(); - // TODO I add, It may error when call delete() - return; - } - - // If this edit is creating the entry for the first time, every index - // must have a value. - if (success && !entry.readable) { - for (int i = 0; i < valueCount; i++) { - if (!editor.written[i]) { - editor.abort(); - throw new IllegalStateException( - "Newly created entry didn't create value for index " - + i); - } - if (!entry.getDirtyFile(i).exists()) { - editor.abort(); - return; - } - } - } - - for (int i = 0; i < valueCount; i++) { - File dirty = entry.getDirtyFile(i); - if (success) { - if (dirty.exists()) { - File clean = entry.getCleanFile(i); - dirty.renameTo(clean); - long oldLength = entry.lengths[i]; - long newLength = clean.length(); - entry.lengths[i] = newLength; - size = size - oldLength + newLength; - } - } else { - deleteIfExists(dirty); - } - } - - redundantOpCount++; - entry.currentEditor = null; - if (entry.readable | success) { - entry.readable = true; - journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() - + '\n'); - if (success) { - entry.sequenceNumber = nextSequenceNumber++; - } - } else { - lruEntries.remove(entry.key); - journalWriter.write(REMOVE + ' ' + entry.key + '\n'); - } - journalWriter.flush(); - - if (size > maxSize || journalRebuildRequired()) { - executorService.submit(cleanupCallable); - } - } - - /** - * We only rebuild the journal when it will halve the size of the journal - * and eliminate at least 2000 ops. - */ - private boolean journalRebuildRequired() { - final int redundantOpCompactThreshold = 2000; - return redundantOpCount >= redundantOpCompactThreshold // - && redundantOpCount >= lruEntries.size(); - } - - /** - * Drops the entry for {@code key} if it exists and can be removed. Entries - * actively being edited cannot be removed. - * - * @return true if an entry was removed. - */ - public synchronized boolean remove(String key) throws IOException { - checkNotClosed(); - validateKey(key); - Entry entry = lruEntries.get(key); - if (entry == null || entry.currentEditor != null) { - return false; - } - - for (int i = 0; i < valueCount; i++) { - File file = entry.getCleanFile(i); - if (file.exists() && !file.delete()) { - throw new IOException("failed to delete " + file); - } - size -= entry.lengths[i]; - entry.lengths[i] = 0; - } - - redundantOpCount++; - journalWriter.append(REMOVE + ' ' + key + '\n'); - lruEntries.remove(key); - - if (journalRebuildRequired()) { - executorService.submit(cleanupCallable); - } - - return true; - } - - /** Returns true if this cache has been closed. */ - public synchronized boolean isClosed() { - return journalWriter == null; - } - - private void checkNotClosed() { - if (journalWriter == null) { - throw new IllegalStateException("cache is closed"); - } - } - - /** Force buffered operations to the filesystem. */ - public synchronized void flush() throws IOException { - checkNotClosed(); - trimToSize(); - journalWriter.flush(); - } - - /** Closes this cache. Stored values will remain on the filesystem. */ - public synchronized void close() throws IOException { - if (journalWriter == null) { - return; // Already closed. - } - for (Entry entry : new ArrayList(lruEntries.values())) { - if (entry.currentEditor != null) { - entry.currentEditor.abort(); - } - } - trimToSize(); - journalWriter.close(); - journalWriter = null; - } - - private void trimToSize() throws IOException { - while (size > maxSize) { - Map.Entry toEvict = lruEntries.entrySet().iterator() - .next(); - remove(toEvict.getKey()); - } - } - - /** - * Closes the cache and deletes all of its stored values. This will delete - * all files in the cache directory including files that weren't created by - * the cache. - */ - public synchronized void delete() throws IOException { - close(); - Util.deleteContents(directory); - // TODO I add - size = 0; - lruEntries.clear(); - rebuildJournal(); - } - - private void validateKey(String key) { - Matcher matcher = LEGAL_KEY_PATTERN.matcher(key); - if (!matcher.matches()) { - throw new IllegalArgumentException( - "keys must match regex [a-z0-9_-]{1,64}: \"" + key + "\""); - } - } - - private static String inputStreamToString(InputStream in) - throws IOException { - return Util.readFully(new InputStreamReader(in, Util.UTF_8)); - } - - /** A snapshot of the values for an entry. */ - public final class Snapshot implements Closeable { - private final String key; - private final long sequenceNumber; - private final InputStream[] ins; - private final long[] lengths; - - private Snapshot(String key, long sequenceNumber, InputStream[] ins, - long[] lengths) { - this.key = key; - this.sequenceNumber = sequenceNumber; - this.ins = ins; - this.lengths = lengths; - } - - /** - * Returns an editor for this snapshot's entry, or null if either the - * entry has changed since this snapshot was created or if another edit - * is in progress. - */ - public Editor edit() throws IOException { - return DiskLruCache.this.edit(key, sequenceNumber); - } - - /** Returns the unbuffered stream with the value for {@code index}. */ - public InputStream getInputStream(int index) { - return ins[index]; - } - - /** Returns the string value for {@code index}. */ - public String getString(int index) throws IOException { - return inputStreamToString(getInputStream(index)); - } - - /** Returns the byte length of the value for {@code index}. */ - public long getLength(int index) { - return lengths[index]; - } - - public void close() { - for (InputStream in : ins) { - Util.closeQuietly(in); - } - } - } - - private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() { - @Override - public void write(int b) throws IOException { - // Eat all writes silently. Nom nom. - } - }; - - /** Edits the values for an entry. */ - public final class Editor { - private final Entry entry; - private final boolean[] written; - private boolean hasErrors; - private boolean committed; - - private Editor(Entry entry) { - this.entry = entry; - this.written = (entry.readable) ? null : new boolean[valueCount]; - } - - /** - * Returns an unbuffered input stream to read the last committed value, - * or null if no value has been committed. - */ - public InputStream newInputStream(int index) throws IOException { - synchronized (DiskLruCache.this) { - if (entry.currentEditor != this) { - throw new IllegalStateException(); - } - if (!entry.readable) { - return null; - } - try { - return new FileInputStream(entry.getCleanFile(index)); - } catch (FileNotFoundException e) { - return null; - } - } - } - - /** - * Returns the last committed value as a string, or null if no value has - * been committed. - */ - public String getString(int index) throws IOException { - InputStream in = newInputStream(index); - return in != null ? inputStreamToString(in) : null; - } - - /** - * Returns a new unbuffered output stream to write the value at - * {@code index}. If the underlying output stream encounters errors when - * writing to the filesystem, this edit will be aborted when - * {@link #commit} is called. The returned output stream does not throw - * IOExceptions. - */ - public OutputStream newOutputStream(int index) throws IOException { - synchronized (DiskLruCache.this) { - if (entry.currentEditor != this) { - throw new IllegalStateException(); - } - if (!entry.readable) { - written[index] = true; - } - File dirtyFile = entry.getDirtyFile(index); - FileOutputStream outputStream; - try { - outputStream = new FileOutputStream(dirtyFile); - } catch (FileNotFoundException e) { - // Attempt to recreate the cache directory. - directory.mkdirs(); - try { - outputStream = new FileOutputStream(dirtyFile); - } catch (FileNotFoundException e2) { - // We are unable to recover. Silently eat the writes. - return NULL_OUTPUT_STREAM; - } - } - return new FaultHidingOutputStream(outputStream); - } - } - - /** Sets the value at {@code index} to {@code value}. */ - public void set(int index, String value) throws IOException { - Writer writer = null; - try { - writer = new OutputStreamWriter(newOutputStream(index), - Util.UTF_8); - writer.write(value); - } finally { - Util.closeQuietly(writer); - } - } - - /** - * Commits this edit so it is visible to readers. This releases the edit - * lock so another edit may be started on the same key. - */ - public void commit() throws IOException { - if (hasErrors) { - completeEdit(this, false); - remove(entry.key); // The previous entry is stale. - } else { - completeEdit(this, true); - } - committed = true; - } - - /** - * Aborts this edit. This releases the edit lock so another edit may be - * started on the same key. - */ - public void abort() throws IOException { - completeEdit(this, false); - } - - public void abortUnlessCommitted() { - if (!committed) { - try { - abort(); - } catch (IOException ignored) { - } - } - } - - private class FaultHidingOutputStream extends FilterOutputStream { - private FaultHidingOutputStream(OutputStream out) { - super(out); - } - - @Override - public void write(int oneByte) { - try { - out.write(oneByte); - } catch (IOException e) { - hasErrors = true; - } - } - - @Override - public void write(byte[] buffer, int offset, int length) { - try { - out.write(buffer, offset, length); - } catch (IOException e) { - hasErrors = true; - } - } - - @Override - public void close() { - try { - out.close(); - } catch (IOException e) { - hasErrors = true; - } - } - - @Override - public void flush() { - try { - out.flush(); - } catch (IOException e) { - hasErrors = true; - } - } - } - } - - private final class Entry { - private final String key; - - /** Lengths of this entry's files. */ - private final long[] lengths; - - /** True if this entry has ever been published. */ - private boolean readable; - - /** The ongoing edit or null if this entry is not being edited. */ - private Editor currentEditor; - - /** - * The sequence number of the most recently committed edit to this - * entry. - */ - private long sequenceNumber; - - private Entry(String key) { - this.key = key; - this.lengths = new long[valueCount]; - } - - public String getLengths() throws IOException { - StringBuilder result = new StringBuilder(); - for (long size : lengths) { - result.append(' ').append(size); - } - return result.toString(); - } - - /** Set lengths using decimal numbers like "10123". */ - private void setLengths(String[] strings) throws IOException { - if (strings.length != valueCount) { - throw invalidLengths(strings); - } - - try { - for (int i = 0; i < strings.length; i++) { - lengths[i] = Long.parseLong(strings[i]); - } - } catch (NumberFormatException e) { - throw invalidLengths(strings); - } - } - - private IOException invalidLengths(String[] strings) throws IOException { - throw new IOException("unexpected journal line: " - + java.util.Arrays.toString(strings)); - } - - public File getCleanFile(int i) { - return new File(directory, key + "." + i); - } - - public File getDirtyFile(int i) { - return new File(directory, key + "." + i + ".tmp"); - } - } -} diff --git a/src/com/jakewharton/disklrucache/StrictLineReader.java b/src/com/jakewharton/disklrucache/StrictLineReader.java deleted file mode 100644 index 783e1ddd0..000000000 --- a/src/com/jakewharton/disklrucache/StrictLineReader.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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.jakewharton.disklrucache; - -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; - -/** - * Buffers input from an {@link InputStream} for reading lines. - * - *

This class is used for buffered reading of lines. For purposes of this class, a line ends - * with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated - * line at end of input is invalid and will be ignored, the caller may use {@code - * hasUnterminatedLine()} to detect it after catching the {@code EOFException}. - * - *

This class is intended for reading input that strictly consists of lines, such as line-based - * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction - * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different - * end-of-input reporting and a more restrictive definition of a line. - * - *

This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 - * and 10, respectively, and the representation of no other character contains these values. - * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1. - * The default charset is US_ASCII. - */ -class StrictLineReader implements Closeable { - private static final byte CR = (byte) '\r'; - private static final byte LF = (byte) '\n'; - - private final InputStream in; - private final Charset charset; - - /* - * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end - * and the data in the range [pos, end) is buffered for reading. At end of input, if there is - * an unterminated line, we set end == -1, otherwise end == pos. If the underlying - * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. - */ - private byte[] buf; - private int pos; - private int end; - - /** - * Constructs a new {@code LineReader} with the specified charset and the default capacity. - * - * @param in the {@code InputStream} to read data from. - * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are - * supported. - * @throws NullPointerException if {@code in} or {@code charset} is null. - * @throws IllegalArgumentException if the specified charset is not supported. - */ - public StrictLineReader(InputStream in, Charset charset) { - this(in, 8192, charset); - } - - /** - * Constructs a new {@code LineReader} with the specified capacity and charset. - * - * @param in the {@code InputStream} to read data from. - * @param capacity the capacity of the buffer. - * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are - * supported. - * @throws NullPointerException if {@code in} or {@code charset} is null. - * @throws IllegalArgumentException if {@code capacity} is negative or zero - * or the specified charset is not supported. - */ - public StrictLineReader(InputStream in, int capacity, Charset charset) { - if (in == null || charset == null) { - throw new NullPointerException(); - } - if (capacity < 0) { - throw new IllegalArgumentException("capacity <= 0"); - } - if (!(charset.equals(Util.US_ASCII))) { - throw new IllegalArgumentException("Unsupported encoding"); - } - - this.in = in; - this.charset = charset; - buf = new byte[capacity]; - } - - /** - * Closes the reader by closing the underlying {@code InputStream} and - * marking this reader as closed. - * - * @throws IOException for errors when closing the underlying {@code InputStream}. - */ - public void close() throws IOException { - synchronized (in) { - if (buf != null) { - buf = null; - in.close(); - } - } - } - - /** - * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"}, - * this end of line marker is not included in the result. - * - * @return the next line from the input. - * @throws IOException for underlying {@code InputStream} errors. - * @throws EOFException for the end of source stream. - */ - public String readLine() throws IOException { - synchronized (in) { - if (buf == null) { - throw new IOException("LineReader is closed"); - } - - // Read more data if we are at the end of the buffered data. - // Though it's an error to read after an exception, we will let {@code fillBuf()} - // throw again if that happens; thus we need to handle end == -1 as well as end == pos. - if (pos >= end) { - fillBuf(); - } - // Try to find LF in the buffered data and return the line if successful. - for (int i = pos; i != end; ++i) { - if (buf[i] == LF) { - int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i; - String res = new String(buf, pos, lineEnd - pos, charset.name()); - pos = i + 1; - return res; - } - } - - // Let's anticipate up to 80 characters on top of those already read. - ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) { - @Override - public String toString() { - int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count; - try { - return new String(buf, 0, length, charset.name()); - } catch (UnsupportedEncodingException e) { - throw new AssertionError(e); // Since we control the charset this will never happen. - } - } - }; - - while (true) { - out.write(buf, pos, end - pos); - // Mark unterminated line in case fillBuf throws EOFException or IOException. - end = -1; - fillBuf(); - // Try to find LF in the buffered data and return the line if successful. - for (int i = pos; i != end; ++i) { - if (buf[i] == LF) { - if (i != pos) { - out.write(buf, pos, i - pos); - } - pos = i + 1; - return out.toString(); - } - } - } - } - } - - /** - * Reads new input data into the buffer. Call only with pos == end or end == -1, - * depending on the desired outcome if the function throws. - */ - private void fillBuf() throws IOException { - int result = in.read(buf, 0, buf.length); - if (result == -1) { - throw new EOFException(); - } - pos = 0; - end = result; - } -} - diff --git a/src/com/jakewharton/disklrucache/Util.java b/src/com/jakewharton/disklrucache/Util.java deleted file mode 100644 index 0a7dba9bc..000000000 --- a/src/com/jakewharton/disklrucache/Util.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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.jakewharton.disklrucache; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.io.Reader; -import java.io.StringWriter; -import java.nio.charset.Charset; - -/** Junk drawer of utility methods. */ -final class Util { - static final Charset US_ASCII = Charset.forName("US-ASCII"); - static final Charset UTF_8 = Charset.forName("UTF-8"); - - private Util() { - } - - static String readFully(Reader reader) throws IOException { - try { - StringWriter writer = new StringWriter(); - char[] buffer = new char[1024]; - int count; - while ((count = reader.read(buffer)) != -1) { - writer.write(buffer, 0, count); - } - return writer.toString(); - } finally { - reader.close(); - } - } - - /** - * Deletes the contents of {@code dir}. Throws an IOException if any file - * could not be deleted, or if {@code dir} is not a readable directory. - */ - static void deleteContents(File dir) throws IOException { - File[] files = dir.listFiles(); - if (files == null) { - throw new IOException("not a readable directory: " + dir); - } - for (File file : files) { - if (file.isDirectory()) { - deleteContents(file); - } - if (!file.delete()) { - throw new IOException("failed to delete file: " + file); - } - } - } - - static void closeQuietly(/*Auto*/Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (RuntimeException rethrown) { - throw rethrown; - } catch (Exception ignored) { - } - } - } -}