From 2df5ddad6c8038a0405e5e86f70759849989132d Mon Sep 17 00:00:00 2001 From: nuclearfog Date: Fri, 19 Jun 2020 20:11:26 +0200 Subject: [PATCH] image view performance improvement --- .../twidda/activity/MediaViewer.java | 21 ++-- .../twidda/adapter/ImageAdapter.java | 98 +++++++++++-------- .../twidda/backend/ImageLoader.java | 23 +++-- .../twidda/backend/holder/ImageHolder.java | 57 +++++++++++ 4 files changed, 139 insertions(+), 60 deletions(-) create mode 100644 app/src/main/java/org/nuclearfog/twidda/backend/holder/ImageHolder.java diff --git a/app/src/main/java/org/nuclearfog/twidda/activity/MediaViewer.java b/app/src/main/java/org/nuclearfog/twidda/activity/MediaViewer.java index e4b92f31..9d3b6d84 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activity/MediaViewer.java +++ b/app/src/main/java/org/nuclearfog/twidda/activity/MediaViewer.java @@ -26,6 +26,7 @@ import org.nuclearfog.twidda.adapter.ImageAdapter.OnImageClickListener; import org.nuclearfog.twidda.backend.ImageLoader; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.helper.ErrorHandler; +import org.nuclearfog.twidda.backend.holder.ImageHolder; import org.nuclearfog.zoomview.ZoomView; import java.text.SimpleDateFormat; @@ -143,7 +144,8 @@ public class MediaViewer extends AppCompatActivity implements OnImageClickListen @Override public void onImageClick(Bitmap image) { - changeImage(image); + zoomImage.reset(); + zoomImage.setImageBitmap(image); } @@ -201,27 +203,16 @@ public class MediaViewer extends AppCompatActivity implements OnImageClickListen } - public void setImage(Bitmap image) { + public void setImage(ImageHolder image) { if (adapter.isEmpty()) { - changeImage(image); + zoomImage.reset(); + zoomImage.setImageBitmap(image.getMiddleSize()); image_progress.setVisibility(View.INVISIBLE); } adapter.addLast(image); } - private void changeImage(Bitmap image) { - int width = zoomImage.getMeasuredWidth(); - if (width > 0 && image.getWidth() > width) { - float ratio = image.getWidth() / (float) width; - int destHeight = (int) (image.getHeight() / ratio); - image = Bitmap.createScaledBitmap(image, width, destHeight, false); - } - zoomImage.reset(); - zoomImage.setImageBitmap(image); - } - - private void storeImage(Bitmap image) { String name = "shitter_" + formatter.format(new Date()); try { diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java b/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java index dee389b9..642c4fd5 100644 --- a/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java @@ -12,21 +12,24 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import org.nuclearfog.twidda.backend.holder.ImageHolder; + import java.util.LinkedList; import java.util.List; import static android.widget.ListPopupWindow.MATCH_PARENT; import static android.widget.ListPopupWindow.WRAP_CONTENT; +import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; -public class ImageAdapter extends Adapter { +public class ImageAdapter extends Adapter { private static final int PICTURE = 0; private static final int LOADING = 1; private OnImageClickListener itemClickListener; - private List images; + private List images; private boolean loading; @@ -38,11 +41,11 @@ public class ImageAdapter extends Adapter { @MainThread - public void addLast(@NonNull Bitmap image) { + public void addLast(@NonNull ImageHolder imageItem) { int imagePos = images.size(); if (imagePos == 0) loading = true; - images.add(image); + images.add(imageItem); notifyItemInserted(imagePos); } @@ -78,56 +81,73 @@ public class ImageAdapter extends Adapter { @NonNull @Override - public ImageAdapter.ImageHolder onCreateViewHolder(@NonNull final ViewGroup parent, int viewType) { - if (viewType == LOADING) { + public ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, int viewType) { + if (viewType == PICTURE) { + ImageView preview = new ImageView(parent.getContext()); + preview.setBackgroundColor(0xffffffff); + preview.setPadding(1, 1, 1, 1); + final ImageItem item = new ImageItem(preview); + preview.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int pos = item.getAdapterPosition(); + if (pos != NO_POSITION) { + Bitmap img = images.get(pos).getMiddleSize(); + itemClickListener.onImageClick(img); + } + } + }); + preview.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + int pos = item.getAdapterPosition(); + if (pos != NO_POSITION) { + Bitmap img = images.get(pos).getOriginalImage(); + itemClickListener.onImageTouch(img); + } + return true; + } + }); + return item; + } else { ProgressBar circle = new ProgressBar(parent.getContext()); LayoutParams param = new LayoutParams(WRAP_CONTENT, MATCH_PARENT); circle.setLayoutParams(param); - return new ImageHolder(circle); - } else { - return new ImageHolder(new ImageView(parent.getContext())); + return new LoadItem(circle); } } @Override - public void onBindViewHolder(@NonNull ImageAdapter.ImageHolder vh, int index) { - if (vh.view instanceof ImageView) { - final Bitmap image = images.get(index); - ImageView imageView = (ImageView) vh.view; - imageView.setImageBitmap(downscale(image)); - imageView.setBackgroundColor(0xffffffff); - imageView.setPadding(1, 1, 1, 1); - imageView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - itemClickListener.onImageClick(image); - } - }); - imageView.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - itemClickListener.onImageTouch(image); - return true; - } - }); + public void onBindViewHolder(@NonNull ViewHolder vh, int index) { + if (vh instanceof ImageItem) { + ImageItem item = (ImageItem) vh; + Bitmap image = images.get(index).getSmallSize(); + item.preview.setImageBitmap(image); } } + /** + * Holder for image + */ + class ImageItem extends ViewHolder { + final ImageView preview; - private Bitmap downscale(Bitmap image) { - float ratio = image.getHeight() / 256.0f; - int destWidth = (int) (image.getWidth() / ratio); - return Bitmap.createScaledBitmap(image, destWidth, 256, false); + ImageItem(ImageView preview) { + super(preview); + this.preview = preview; + } } + /** + * Holder for progress circle + */ + class LoadItem extends ViewHolder { + final ProgressBar circle; - static class ImageHolder extends ViewHolder { - final View view; - - ImageHolder(View view) { - super(view); - this.view = view; + LoadItem(ProgressBar circle) { + super(circle); + this.circle = circle; } } diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/ImageLoader.java b/app/src/main/java/org/nuclearfog/twidda/backend/ImageLoader.java index e20fb6e7..e6b18944 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/ImageLoader.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/ImageLoader.java @@ -2,6 +2,7 @@ package org.nuclearfog.twidda.backend; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Point; import android.os.AsyncTask; import androidx.annotation.NonNull; @@ -10,6 +11,7 @@ import androidx.annotation.Nullable; import org.nuclearfog.twidda.activity.MediaViewer; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.engine.TwitterEngine; +import org.nuclearfog.twidda.backend.holder.ImageHolder; import java.lang.ref.WeakReference; @@ -18,12 +20,15 @@ import java.lang.ref.WeakReference; * * @see MediaViewer */ -public class ImageLoader extends AsyncTask { +public class ImageLoader extends AsyncTask { + + private static final float PREV_HEIGHT_RATIO = 5.0f; @Nullable private EngineException err; - private WeakReference callback; private TwitterEngine mTwitter; + private WeakReference callback; + private float previewHeight, zoomPreview; /** @@ -34,6 +39,10 @@ public class ImageLoader extends AsyncTask { public ImageLoader(@NonNull MediaViewer callback) { this.callback = new WeakReference<>(callback); mTwitter = TwitterEngine.getInstance(callback); + Point displaySize = new Point(); + callback.getWindowManager().getDefaultDisplay().getSize(displaySize); + zoomPreview = displaySize.x; + previewHeight = displaySize.y / PREV_HEIGHT_RATIO; } @@ -48,7 +57,8 @@ public class ImageLoader extends AsyncTask { image = BitmapFactory.decodeFile(link); } if (image != null) { - publishProgress(image); + ImageHolder images = new ImageHolder(image, previewHeight, zoomPreview); + publishProgress(images); } } return true; @@ -62,9 +72,10 @@ public class ImageLoader extends AsyncTask { @Override - protected void onProgressUpdate(Bitmap[] btm) { - if (callback.get() != null) - callback.get().setImage(btm[0]); + protected void onProgressUpdate(ImageHolder[] images) { + if (callback.get() != null) { + callback.get().setImage(images[0]); + } } diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/holder/ImageHolder.java b/app/src/main/java/org/nuclearfog/twidda/backend/holder/ImageHolder.java new file mode 100644 index 00000000..96bcec75 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/backend/holder/ImageHolder.java @@ -0,0 +1,57 @@ +package org.nuclearfog.twidda.backend.holder; + +import android.graphics.Bitmap; + +import androidx.annotation.NonNull; + +/** + * Container class for Bitmap images and previews + */ +public class ImageHolder { + + private Bitmap smallImage, middleImage, fullImage; + + + public ImageHolder(@NonNull Bitmap fullImage, float smallImageHeight, float middleImageWidth) { + this.fullImage = fullImage; + + float ratio = fullImage.getHeight() / smallImageHeight; + int destWidth = (int) (fullImage.getWidth() / ratio); + smallImage = Bitmap.createScaledBitmap(fullImage, destWidth, (int) smallImageHeight, false); + + if (middleImageWidth > 0 && fullImage.getWidth() > middleImageWidth) { + ratio = fullImage.getWidth() / middleImageWidth; + int destHeight = (int) (fullImage.getHeight() / ratio); + middleImage = Bitmap.createScaledBitmap(fullImage, (int) middleImageWidth, destHeight, false); + } else { + middleImage = fullImage; + } + } + + /** + * get small sized image + * + * @return Image Bitmap + */ + public Bitmap getSmallSize() { + return smallImage; + } + + /** + * get Middle sized image + * + * @return Image Bitmap + */ + public Bitmap getMiddleSize() { + return middleImage; + } + + /** + * get Original Image + * + * @return Image Bitmap + */ + public Bitmap getOriginalImage() { + return fullImage; + } +} \ No newline at end of file