22
33import android .app .Activity ;
44import android .content .Context ;
5+ import android .content .res .Resources ;
6+ import android .graphics .Bitmap ;
7+ import android .graphics .BitmapFactory ;
58import android .graphics .Color ;
9+ import android .graphics .drawable .BitmapDrawable ;
10+ import android .graphics .drawable .Drawable ;
11+ import android .os .AsyncTask ;
612import android .support .annotation .ColorRes ;
713import android .support .v7 .widget .CardView ;
814import android .support .v7 .widget .RecyclerView ;
1521import org .buildmlearn .toolkit .R ;
1622import 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