Skip to content

Commit 75c2e21

Browse files
committed
Added asynchronous loading of template thumbnail
1 parent 4f5e5e7 commit 75c2e21

File tree

1 file changed

+134
-1
lines changed

1 file changed

+134
-1
lines changed

source-code/app/src/main/java/org/buildmlearn/toolkit/adapter/TemplateAdapter.java

+134-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
import android.app.Activity;
44
import android.content.Context;
5+
import android.content.res.Resources;
6+
import android.graphics.Bitmap;
7+
import android.graphics.BitmapFactory;
58
import android.graphics.Color;
9+
import android.graphics.drawable.BitmapDrawable;
10+
import android.graphics.drawable.Drawable;
11+
import android.os.AsyncTask;
612
import android.support.annotation.ColorRes;
713
import android.support.v7.widget.CardView;
814
import android.support.v7.widget.RecyclerView;
@@ -15,6 +21,8 @@
1521
import org.buildmlearn.toolkit.R;
1622
import org.buildmlearn.toolkit.model.Template;
1723

24+
import java.lang.ref.WeakReference;
25+
1826
/**
1927
* @brief Adapter used for showing Templates available in the toolkit
2028
* <p>
@@ -32,6 +40,35 @@ public TemplateAdapter(Context context) {
3240
this.context = context;
3341
}
3442

43+
public static boolean cancelPotentialWork(int data, ImageView imageView) {
44+
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
45+
46+
if (bitmapWorkerTask != null) {
47+
final int bitmapData = bitmapWorkerTask.data;
48+
// If bitmapData is not yet set or it differs from the new data
49+
if (bitmapData == 0 || bitmapData != data) {
50+
// Cancel previous task
51+
bitmapWorkerTask.cancel(true);
52+
} else {
53+
// The same work is already in progress
54+
return false;
55+
}
56+
}
57+
// No task associated with the ImageView, or an existing task was cancelled
58+
return true;
59+
}
60+
61+
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
62+
if (imageView != null) {
63+
final Drawable drawable = imageView.getDrawable();
64+
if (drawable instanceof AsyncDrawable) {
65+
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
66+
return asyncDrawable.getBitmapWorkerTask();
67+
}
68+
}
69+
return null;
70+
}
71+
3572
public void setOnClickListener(ViewHolder.SetOnClickListener clickListener) {
3673
this.listener = clickListener;
3774
}
@@ -67,12 +104,18 @@ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
67104

68105
vh.getTitle().setText(template.getTitle());
69106
vh.getDescription().setText(template.getDescription());
70-
vh.getImage().setImageResource(template.getImage());
71107

72108
int color = colors[position % colors.length].getColor();
73109
vh.getCardView().setCardBackgroundColor(color);
74110
vh.setItemClickListener(listener);
75111

112+
if (cancelPotentialWork(template.getImage(), vh.getImage())) {
113+
final BitmapWorkerTask task = new BitmapWorkerTask(context, vh.getImage());
114+
final AsyncDrawable asyncDrawable =
115+
new AsyncDrawable(context.getResources(), null, task);
116+
vh.getImage().setImageDrawable(asyncDrawable);
117+
task.execute(template.getImage());
118+
}
76119
}
77120

78121
@Override
@@ -170,4 +213,94 @@ public interface SetOnClickListener {
170213
void onItemClick(int position);
171214
}
172215
}
216+
217+
static class AsyncDrawable extends BitmapDrawable {
218+
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
219+
220+
public AsyncDrawable(Resources res, Bitmap bitmap,
221+
BitmapWorkerTask bitmapWorkerTask) {
222+
super(res, bitmap);
223+
bitmapWorkerTaskReference =
224+
new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
225+
}
226+
227+
public BitmapWorkerTask getBitmapWorkerTask() {
228+
return bitmapWorkerTaskReference.get();
229+
}
230+
}
231+
232+
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
233+
private final WeakReference<ImageView> imageViewReference;
234+
private int data = 0;
235+
private Context mContext;
236+
237+
public BitmapWorkerTask(Context context, ImageView imageView) {
238+
// Use a WeakReference to ensure the ImageView can be garbage collected
239+
mContext = context;
240+
imageViewReference = new WeakReference<ImageView>(imageView);
241+
}
242+
243+
// Decode image in background.
244+
@Override
245+
protected Bitmap doInBackground(Integer... params) {
246+
data = params[0];
247+
return decodeSampledBitmapFromResource(context.getResources(), data, 141, 180);
248+
}
249+
250+
// Once complete, see if ImageView is still around and set bitmap.
251+
@Override
252+
protected void onPostExecute(Bitmap bitmap) {
253+
if (isCancelled()) {
254+
bitmap = null;
255+
}
256+
257+
if (imageViewReference != null && bitmap != null) {
258+
final ImageView imageView = imageViewReference.get();
259+
final BitmapWorkerTask bitmapWorkerTask =
260+
getBitmapWorkerTask(imageView);
261+
if (this == bitmapWorkerTask && imageView != null) {
262+
imageView.setImageBitmap(bitmap);
263+
}
264+
}
265+
}
266+
267+
public Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
268+
int reqWidth, int reqHeight) {
269+
270+
// First decode with inJustDecodeBounds=true to check dimensions
271+
final BitmapFactory.Options options = new BitmapFactory.Options();
272+
options.inJustDecodeBounds = true;
273+
BitmapFactory.decodeResource(res, resId, options);
274+
275+
// Calculate inSampleSize
276+
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
277+
278+
// Decode bitmap with inSampleSize set
279+
options.inJustDecodeBounds = false;
280+
return BitmapFactory.decodeResource(res, resId, options);
281+
}
282+
283+
public int calculateInSampleSize(
284+
BitmapFactory.Options options, int reqWidth, int reqHeight) {
285+
// Raw height and width of image
286+
final int height = options.outHeight;
287+
final int width = options.outWidth;
288+
int inSampleSize = 1;
289+
290+
if (height > reqHeight || width > reqWidth) {
291+
292+
final int halfHeight = height / 2;
293+
final int halfWidth = width / 2;
294+
295+
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
296+
// height and width larger than the requested height and width.
297+
while ((halfHeight / inSampleSize) >= reqHeight
298+
&& (halfWidth / inSampleSize) >= reqWidth) {
299+
inSampleSize *= 2;
300+
}
301+
}
302+
303+
return inSampleSize;
304+
}
305+
}
173306
}

0 commit comments

Comments
 (0)