From d9f56830a4bc9284e120ec8fceba391f5ac2b2df Mon Sep 17 00:00:00 2001 From: seven332 Date: Fri, 11 Mar 2016 14:09:01 +0800 Subject: [PATCH] Use Bitmap for thumb instead of Image --- .../com/hippo/drawable/ImageDrawable.java | 175 ----------------- .../java/com/hippo/drawable/ImageWrapper.java | 180 ------------------ .../com/hippo/drawable/UnikeryDrawable.java | 29 +-- ...geWrapperHelper.java => BitmapHelper.java} | 36 ++-- .../com/hippo/ehviewer/EhApplication.java | 20 +- .../java/com/hippo/text/URLImageGetter.java | 10 +- .../java/com/hippo/widget/LoadImageView.java | 78 ++------ beerbelly | 2 +- conaco | 2 +- 9 files changed, 50 insertions(+), 482 deletions(-) delete mode 100644 app/src/main/java/com/hippo/drawable/ImageDrawable.java delete mode 100644 app/src/main/java/com/hippo/drawable/ImageWrapper.java rename app/src/main/java/com/hippo/ehviewer/{ImageWrapperHelper.java => BitmapHelper.java} (55%) diff --git a/app/src/main/java/com/hippo/drawable/ImageDrawable.java b/app/src/main/java/com/hippo/drawable/ImageDrawable.java deleted file mode 100644 index b4cee5723..000000000 --- a/app/src/main/java/com/hippo/drawable/ImageDrawable.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2016 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.drawable; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; - -import com.hippo.yorozuya.MathUtils; - -import java.util.ArrayList; -import java.util.List; - -public class ImageDrawable extends Drawable implements ImageWrapper.Callback, Animatable { - - private static final int TILE_SIZE = 512; - - private ImageWrapper mImageWrapper; - private Paint mPaint; - - private List mTileList; - - private static class Tile { - Bitmap bitmap; - int w; - int h; - int x; - int y; - } - - private static final BitmapPool sBitmapPool = new BitmapPool(); - - public ImageDrawable(@NonNull ImageWrapper imageWrapper) { - mImageWrapper = imageWrapper; - mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); - mTileList = createTileArray(); - - // Render first frame - render(); - - // Add callback - imageWrapper.addCallback(this); - } - - private List createTileArray() { - int width = mImageWrapper.getWidth(); - int height = mImageWrapper.getHeight(); - int capacity = MathUtils.clamp(MathUtils.ceilDivide(width, TILE_SIZE) * - MathUtils.ceilDivide(height, TILE_SIZE), 0, 100); - List tiles = new ArrayList<>(capacity); - - for (int x = 0; x < width; x += TILE_SIZE) { - int w = Math.min(TILE_SIZE, width - x); - for (int y = 0; y < height; y += TILE_SIZE) { - int h = Math.min(TILE_SIZE, height - y); - Tile tile = new Tile(); - tile.x = x; - tile.y = y; - tile.w = w; - tile.h = h; - tile.bitmap = sBitmapPool.get(w, h); - tiles.add(tile); - } - } - - return tiles; - } - - private void render() { - ImageWrapper imageWrapper = mImageWrapper; - if (imageWrapper.isRecycled()) { - return; - } - - List tiles = mTileList; - for (int i = 0, length = tiles.size(); i < length; i++) { - Tile tile = tiles.get(i); - if (tile.bitmap != null) { - imageWrapper.render(tile.x, tile.y, tile.bitmap, 0, 0, tile.w, tile.h, false, 0); - } - } - } - - @Override - public int getIntrinsicWidth() { - return mImageWrapper.getWidth(); - } - - @Override - public int getIntrinsicHeight() { - return mImageWrapper.getHeight(); - } - - @Override - public void draw(Canvas canvas) { - List tiles = mTileList; - for (int i = 0, length = tiles.size(); i < length; i++) { - Tile tile = tiles.get(i); - if (tile.bitmap != null) { - canvas.drawBitmap(tile.bitmap, tile.x, tile.y, mPaint); - } - } - } - - @Override - public void setAlpha(int alpha) { - mPaint.setAlpha(alpha); - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - mPaint.setColorFilter(colorFilter); - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - public void recycle() { - mImageWrapper.removeCallback(this); - - // Free tile's bitmap - List tiles = mTileList; - for (int i = 0, length = tiles.size(); i < length; i++) { - Tile tile = tiles.get(i); - sBitmapPool.put(tile.bitmap); - tile.bitmap = null; - } - } - - @Override - public void renderImage(ImageWrapper who) { - render(); - } - - @Override - public void invalidateImage(ImageWrapper who) { - invalidateSelf(); - } - - @Override - public void start() { - mImageWrapper.start(); - } - - @Override - public void stop() { - mImageWrapper.stop(); - } - - @Override - public boolean isRunning() { - return mImageWrapper.isRunning(); - } -} diff --git a/app/src/main/java/com/hippo/drawable/ImageWrapper.java b/app/src/main/java/com/hippo/drawable/ImageWrapper.java deleted file mode 100644 index b631a5916..000000000 --- a/app/src/main/java/com/hippo/drawable/ImageWrapper.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2016 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.drawable; - -import android.graphics.Bitmap; -import android.graphics.drawable.Animatable; -import android.support.annotation.NonNull; -import android.util.Log; - -import com.hippo.image.Image; -import com.hippo.yorozuya.SimpleHandler; - -import java.lang.ref.WeakReference; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -public class ImageWrapper implements Animatable, Runnable { - - private static final String TAG = ImageWrapper.class.getSimpleName(); - - private final Image mImage; - - private boolean mRunning = false; - - private final Set> mCallbackSet = new LinkedHashSet<>(); - - public ImageWrapper(@NonNull Image image) { - mImage = image; - } - - public int getWidth() { - return mImage.getWidth(); - } - - public int getHeight() { - return mImage.getHeight(); - } - - public void render(int srcX, int srcY, Bitmap dst, int dstX, int dstY, - int width, int height, boolean fillBlank, int defaultColor) { - mImage.render(srcX, srcY, dst, dstX, dstY, - width, height, fillBlank, defaultColor); - } - - public int getFrameCount() { - return mImage.getFrameCount(); - } - - public void recycle() { - stop(); - mImage.recycle(); - } - - public boolean isRecycled() { - return mImage.isRecycled(); - } - - public boolean isLarge() { - return mImage.getWidth() * mImage.getHeight() > 512 * 512; - } - - public void addCallback(@NonNull Callback callback) { - final Iterator> iterator = mCallbackSet.iterator(); - Callback c; - while (iterator.hasNext()) { - c = iterator.next().get(); - if (c == null) { - // Remove from the set if the reference has been cleared or - // it can't be used. - iterator.remove(); - } else if (c == callback) { - return; - } - } - - mCallbackSet.add(new WeakReference<>(callback)); - } - - public void removeCallback(@NonNull Callback callback) { - final Iterator> iterator = mCallbackSet.iterator(); - Callback c; - while (iterator.hasNext()) { - c = iterator.next().get(); - if (c == null) { - // Remove from the set if the reference has been cleared or - // it can't be used. - iterator.remove(); - } else if (c == callback) { - iterator.remove(); - return; - } - } - } - - @Override - public void start() { - if (mImage.isRecycled() || mImage.getFrameCount() <= 1 || mRunning) { - return; - } - - mRunning = true; - - SimpleHandler.getInstance().postDelayed(this, Math.max(0, mImage.getDelay())); - } - - @Override - public void stop() { - mRunning = false; - SimpleHandler.getInstance().removeCallbacks(this); - } - - @Override - public boolean isRunning() { - return mRunning; - } - - private boolean notifyUpdate() { - boolean hasCallback = false; - final Iterator> iterator = mCallbackSet.iterator(); - Callback callback; - while (iterator.hasNext()) { - callback = iterator.next().get(); - if (callback != null) { - hasCallback = true; - callback.renderImage(this); - callback.invalidateImage(this); - } else { - // Remove from the set if the reference has been cleared or - // it can't be used. - iterator.remove(); - } - } - return hasCallback; - } - - @Override - public void run() { - //Log.i(TAG, this + " run"); - - // Check recycled - if (mImage.isRecycled()) { - mRunning = false; - return; - } - - mImage.advance(); - - if (notifyUpdate()) { - if (mRunning) { - SimpleHandler.getInstance().postDelayed(this, Math.max(0, mImage.getDelay())); - } - } else { - // No callback ? Stop now - Log.w(TAG, "No callback"); - mRunning = false; - } - } - - public interface Callback { - - void renderImage(ImageWrapper who); - - void invalidateImage(ImageWrapper who); - } -} diff --git a/app/src/main/java/com/hippo/drawable/UnikeryDrawable.java b/app/src/main/java/com/hippo/drawable/UnikeryDrawable.java index ce6860841..414d61f3a 100644 --- a/app/src/main/java/com/hippo/drawable/UnikeryDrawable.java +++ b/app/src/main/java/com/hippo/drawable/UnikeryDrawable.java @@ -16,6 +16,8 @@ package com.hippo.drawable; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.widget.TextView; @@ -24,13 +26,13 @@ import com.hippo.conaco.Conaco; import com.hippo.conaco.Unikery; import com.hippo.conaco.ValueHolder; -public class UnikeryDrawable extends WrapDrawable implements Unikery { +public class UnikeryDrawable extends WrapDrawable implements Unikery { private int mTaskId = Unikery.INVALID_ID; - private TextView mTextView; + private final TextView mTextView; - private ValueHolder mHolder; + private ValueHolder mHolder; public UnikeryDrawable(TextView textView) { mTextView = textView; @@ -82,40 +84,23 @@ public class UnikeryDrawable extends WrapDrawable implements Unikery holder, Conaco.Source source) { + public boolean onGetObject(@NonNull ValueHolder holder, Conaco.Source source) { holder.obtain(this); removeDrawableAndHolder(); mHolder = holder; - ImageWrapper imageWrapper = holder.getValue(); - Drawable drawable = new ImageDrawable(imageWrapper); - imageWrapper.start(); + Drawable drawable = new BitmapDrawable(holder.getValue()); setDrawable(drawable); diff --git a/app/src/main/java/com/hippo/ehviewer/ImageWrapperHelper.java b/app/src/main/java/com/hippo/ehviewer/BitmapHelper.java similarity index 55% rename from app/src/main/java/com/hippo/ehviewer/ImageWrapperHelper.java rename to app/src/main/java/com/hippo/ehviewer/BitmapHelper.java index 5a9955fb7..8a6d6c9fe 100644 --- a/app/src/main/java/com/hippo/ehviewer/ImageWrapperHelper.java +++ b/app/src/main/java/com/hippo/ehviewer/BitmapHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Hippo Seven + * Copyright 2016 Hippo Seven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,32 +16,26 @@ package com.hippo.ehviewer; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.hippo.conaco.ValueHelper; import com.hippo.conaco.ValueHolder; -import com.hippo.drawable.ImageWrapper; -import com.hippo.image.Image; import com.hippo.yorozuya.io.InputStreamPipe; -public class ImageWrapperHelper implements ValueHelper { +import java.io.IOException; - private static final String TAG = ImageWrapperHelper.class.getSimpleName(); +public class BitmapHelper implements ValueHelper { @Nullable @Override - public ImageWrapper decode(@NonNull InputStreamPipe isPipe) { + public Bitmap decode(@NonNull InputStreamPipe isPipe) { try { isPipe.obtain(); - Image image = Image.decode(isPipe.open(), false); - if (image != null) { - return new ImageWrapper(image); - } else { - return null; - } - } catch (Exception e) { - e.printStackTrace(); + return BitmapFactory.decodeStream(isPipe.open()); + } catch (IOException e) { return null; } finally { isPipe.close(); @@ -50,19 +44,15 @@ public class ImageWrapperHelper implements ValueHelper { } @Override - public int sizeOf(@NonNull String key, @NonNull ImageWrapper value) { - return value.getWidth() * value.getHeight() * 4; + public int sizeOf(@NonNull String key, @NonNull Bitmap value) { + return value.getByteCount(); } @Override - public void onRemove(@NonNull String key, @NonNull ValueHolder oldValue) { - if (oldValue.isFree()) { - oldValue.getValue().recycle(); - } - } + public void onRemove(@NonNull String key, @NonNull ValueHolder oldValue) {} @Override - public boolean useMemoryCache(@NonNull String key, ValueHolder holder) { - return holder == null || !holder.getValue().isLarge(); + public boolean useMemoryCache(@NonNull String key, ValueHolder holder) { + return true; } } diff --git a/app/src/main/java/com/hippo/ehviewer/EhApplication.java b/app/src/main/java/com/hippo/ehviewer/EhApplication.java index bc43887b9..7235d8aea 100644 --- a/app/src/main/java/com/hippo/ehviewer/EhApplication.java +++ b/app/src/main/java/com/hippo/ehviewer/EhApplication.java @@ -18,6 +18,7 @@ package com.hippo.ehviewer; import android.app.ActivityManager; import android.content.Context; +import android.graphics.Bitmap; import android.os.Debug; import android.support.annotation.NonNull; import android.util.Log; @@ -25,7 +26,6 @@ import android.util.SparseArray; import com.hippo.beerbelly.LruCacheEx; import com.hippo.conaco.Conaco; -import com.hippo.drawable.ImageWrapper; import com.hippo.ehviewer.client.EhClient; import com.hippo.ehviewer.client.EhCookieStore; import com.hippo.ehviewer.client.data.GalleryDetail; @@ -58,8 +58,8 @@ public class EhApplication extends SceneApplication { private EhCookieStore mEhCookieStore; private EhClient mEhClient; private OkHttpClient mOkHttpClient; - private ImageWrapperHelper mImageWrapperHelper; - private Conaco mConaco; + private BitmapHelper mBitmapHelper; + private Conaco mConaco; private LruCacheEx mGalleryDetailCache; private LruCacheEx mLargePreviewSetCache; private LruCacheEx mPreviewPagesCache; @@ -170,12 +170,12 @@ public class EhApplication extends SceneApplication { } @NonNull - public static ImageWrapperHelper getImageWrapperHelper(@NonNull Context context) { + public static BitmapHelper getBitmapHelper(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); - if (application.mImageWrapperHelper == null) { - application.mImageWrapperHelper = new ImageWrapperHelper(); + if (application.mBitmapHelper == null) { + application.mBitmapHelper = new BitmapHelper(); } - return application.mImageWrapperHelper; + return application.mBitmapHelper; } private static int getMemoryCacheMaxSize(Context context) { @@ -186,17 +186,17 @@ public class EhApplication extends SceneApplication { } @NonNull - public static Conaco getConaco(@NonNull Context context) { + public static Conaco getConaco(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mConaco == null) { - Conaco.Builder builder = new Conaco.Builder<>(); + Conaco.Builder builder = new Conaco.Builder<>(); builder.hasMemoryCache = true; builder.memoryCacheMaxSize = getMemoryCacheMaxSize(context); builder.hasDiskCache = true; builder.diskCacheDir = new File(context.getCacheDir(), "thumb"); builder.diskCacheMaxSize = 80 * 1024 * 1024; // 80MB builder.okHttpClient = getOkHttpClient(context); - builder.objectHelper = getImageWrapperHelper(context); + builder.objectHelper = getBitmapHelper(context); builder.debug = DEBUG_CONACO; application.mConaco = builder.build(); } diff --git a/app/src/main/java/com/hippo/text/URLImageGetter.java b/app/src/main/java/com/hippo/text/URLImageGetter.java index 835ab1b69..7d34fc0df 100644 --- a/app/src/main/java/com/hippo/text/URLImageGetter.java +++ b/app/src/main/java/com/hippo/text/URLImageGetter.java @@ -16,20 +16,20 @@ package com.hippo.text; +import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.widget.TextView; import com.hippo.conaco.Conaco; import com.hippo.conaco.ConacoTask; -import com.hippo.drawable.ImageWrapper; import com.hippo.drawable.UnikeryDrawable; public class URLImageGetter implements Html.ImageGetter { - private TextView mTextView; - private Conaco mConaco; + private final TextView mTextView; + private final Conaco mConaco; - public URLImageGetter(TextView textView, Conaco conaco) { + public URLImageGetter(TextView textView, Conaco conaco) { mTextView = textView; mConaco = conaco; } @@ -37,7 +37,7 @@ public class URLImageGetter implements Html.ImageGetter { @Override public Drawable getDrawable(String source) { UnikeryDrawable drawable = new UnikeryDrawable(mTextView); - mConaco.load(new ConacoTask.Builder().setUnikery(drawable).setUrl(source).setKey(source)); + mConaco.load(new ConacoTask.Builder().setUnikery(drawable).setUrl(source).setKey(source)); return drawable; } } diff --git a/app/src/main/java/com/hippo/widget/LoadImageView.java b/app/src/main/java/com/hippo/widget/LoadImageView.java index 8fb8ee841..fa78e3861 100644 --- a/app/src/main/java/com/hippo/widget/LoadImageView.java +++ b/app/src/main/java/com/hippo/widget/LoadImageView.java @@ -18,7 +18,9 @@ package com.hippo.widget; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; @@ -32,24 +34,22 @@ import com.hippo.conaco.ConacoTask; import com.hippo.conaco.DataContainer; import com.hippo.conaco.Unikery; import com.hippo.conaco.ValueHolder; -import com.hippo.drawable.ImageDrawable; -import com.hippo.drawable.ImageWrapper; import com.hippo.ehviewer.EhApplication; import com.hippo.ehviewer.R; -public class LoadImageView extends FixedAspectImageView implements Unikery, +public class LoadImageView extends FixedAspectImageView implements Unikery, View.OnClickListener, View.OnLongClickListener { private int mTaskId = Unikery.INVALID_ID; - private Conaco mConaco; + private Conaco mConaco; private String mKey; private String mUrl; private DataContainer mContainer; private boolean mUseNetwork; - private ValueHolder mHolder; + private ValueHolder mHolder; private boolean mFailed; @@ -173,7 +173,7 @@ public class LoadImageView extends FixedAspectImageView implements Unikery builder = new ConacoTask.Builder() + ConacoTask.Builder builder = new ConacoTask.Builder() .setUnikery(this) .setKey(key) .setUrl(url) @@ -213,67 +213,15 @@ public class LoadImageView extends FixedAspectImageView implements Unikery 0) { - drawable = tDrawable.getDrawable(number - 1); - } - } - if (drawable instanceof ImageDrawable) { - ((ImageDrawable) drawable).recycle(); - } setImageDrawable(null); // Remove holder if (mHolder != null) { mHolder.release(this); - - ImageWrapper imageWrapper = mHolder.getValue(); - if (mHolder.isFree()) { - // ImageWrapper is free, stop animate - imageWrapper.stop(); - if (!mHolder.isInMemoryCache()) { - // ImageWrapper is not needed any more, recycle it - imageWrapper.recycle(); - } - } - mHolder = null; } } - public void start() { - Drawable drawable = getDrawable(); - if (drawable instanceof TransitionDrawable) { - TransitionDrawable tDrawable = (TransitionDrawable) drawable; - int number = tDrawable.getNumberOfLayers(); - if (number > 0) { - drawable = tDrawable.getDrawable(number - 1); - } - } - - if (drawable instanceof ImageDrawable) { - ((ImageDrawable) drawable).start(); - } - } - - public void stop() { - Drawable drawable = getDrawable(); - if (drawable instanceof TransitionDrawable) { - TransitionDrawable tDrawable = (TransitionDrawable) drawable; - int number = tDrawable.getNumberOfLayers(); - if (number > 0) { - drawable = tDrawable.getDrawable(number - 1); - } - } - - if (drawable instanceof ImageDrawable) { - ((ImageDrawable) drawable).stop(); - } - } - @Override public void onMiss(Conaco.Source source) { if (source == Conaco.Source.MEMORY) { @@ -290,7 +238,7 @@ public class LoadImageView extends FixedAspectImageView implements Unikery holder, Conaco.Source source) { + public boolean onGetObject(@NonNull ValueHolder holder, Conaco.Source source) { // Release mKey = null; mUrl = null; @@ -301,12 +249,10 @@ public class LoadImageView extends FixedAspectImageView implements Unikery