Android Application Development asynchronous loading images

As we all know Android application developers can not do time-consuming operation on the UI thread, otherwise it will pop up annoying ANR window.

If you need to load application development time from the network, disk images or other non-memory resources, because the load time will be influenced by other factors (such as disk, network, image size, CPU, etc.), it is easy to produce time-consuming operation. So to avoid carrying out similar operations in the UI thread. Today and share with you how to load your images via AsyncTask asynchronous multi-threading and how to deal with concurrency issues.

How to use AsyncTask Load picture?

Resources can be easily loaded by AysncTask start a background thread, then returns the results to the UI thread. When it is used, it needs to create and implement a subclass of the corresponding method, and the following is a through AysncTask decodeSampledBitmapFromResource () method to load a large picture in the example ImageView:

 1 class BitmapWorkerTask extends AsyncTask {
 2     private final WeakReference imageViewReference;
 3     private int data = 0;
 4                                                                        
 5     public BitmapWorkerTask(ImageView imageView) {
 6         // Use a WeakReference to ensure the ImageView can be garbage collected
 7         imageViewReference = new WeakReference(imageView);
 8     }
 9                                                                                                                                                                                       
10     // Decode image in background.
11     @Override
12     protected Bitmap doInBackground(Integer... params) {
13         data = params[0];
14         return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
15     }
16                                                                                                                                                                                     
17     // Once complete, see if ImageView is still around and set bitmap.
18     @Override
19     protected void onPostExecute(Bitmap bitmap) {
20         if (imageViewReference != null && bitmap != null) {
21             final ImageView imageView = imageViewReference.get();
22             if (imageView != null) {
23                 imageView.setImageBitmap(bitmap);
24             }
25         }
26     }
27 }

The reason for using WeakReference save the ImageView is to ensure AsyncTask does not prevent its recycling, so when the end of the task can not guarantee Imageview there when memory is tight, so you should verify it (in this case in onPostExecute before if the user closes Activity, change system settings or the end of Task, ImageView may be recycled).

By the way, we can be loaded asynchronously picture:

1 public void loadBitmap(int resId, ImageView imageView) {
2     BitmapWorkerTask task = new BitmapWorkerTask(imageView);
3     task.execute(resId);
4 }

How to deal with concurrency?

View common components like ListView, GridView other for efficient memory utility, the system will no longer use the user performing a scrolling operation when the child View View resource recovery ,, With the above manner will introduce additional image loading a problem. If you turn AsyncTask in each sub-View is not guaranteed when the task is completed, the associated View has already been recovered. In addition, we can not guarantee the order in which they finished loading

We can save a reference to the AsyncTask ImageView associated Drawable, check whether there is a reference when the task is completed.

Create a dedicated Drawable subclass storage tasks referenced thread. So that when the task is completed to set a picture in the ImageView

 1 static class AsyncDrawable extends BitmapDrawable {
 2     private final WeakReference bitmapWorkerTaskReference;
 3     public AsyncDrawable(Resources res, Bitmap bitmap,
 4             BitmapWorkerTask bitmapWorkerTask) {
 5         super(res, bitmap);
 6         bitmapWorkerTaskReference =
 7             new WeakReference(bitmapWorkerTask);
 8     }
 9                                                                  
10     public BitmapWorkerTask getBitmapWorkerTask() {
11         return bitmapWorkerTaskReference.get();
12     }
13 }

Before performing BitmapTask, you can create AsyncDrawable and bind it to the ImageView

1 public void loadBitmap(int resId, ImageView imageView) {
2     if (cancelPotentialWork(resId, imageView)) {
3         final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
4         final AsyncDrawable asyncDrawable =
5                 new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
6         imageView.setImageDrawable(asyncDrawable);
7         task.execute(resId);
8     }
9 }

The above code by cancelPotentialWork determine whether there has been a running task in the ImageView binding, if so, cancel it by performing the task cancel method, of course, did not arise frequently,

Here is the cancelPotentialWork of:

 1 public static boolean cancelPotentialWork(int data, ImageView imageView) {
 2     final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
 3               
 4     if (bitmapWorkerTask != null) {
 5         final int bitmapData = bitmapWorkerTask.data;
 6         if (bitmapData != data) {
 7             // Cancel previous task
 8             bitmapWorkerTask.cancel(true);
 9         } else {
10             // The same work is already in progress
11             return false;
12         }
13     }
14     // No task associated with the ImageView, or an existing task was cancelled
15     return true;
16 }

Here is a helper method to find asynchronous tasks associated with it by ImageView;

 1 private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
 2    if (imageView != null) {
 3        final Drawable drawable = imageView.getDrawable();
 4        if (drawable instanceof AsyncDrawable) {
 5            final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
 6            return asyncDrawable.getBitmapWorkerTask();
 7        }
 8     }
 9     return null;
10 }

Next you need to perform update operations in BitmapWorkerTask in onPostExecute in

First check whether to cancel the task, such as row after more ImageView associated with:

 1 class BitmapWorkerTask extends AsyncTask {
 2     ...                                                                                                                                    
 3     @Override
 4     protected void onPostExecute(Bitmap bitmap) {
 5         if (isCancelled()) {
 6             bitmap = null;
 7         }                                                                                                                             
 8         if (imageViewReference != null && bitmap != null) {
 9             final ImageView imageView = imageViewReference.get();
10             final BitmapWorkerTask bitmapWorkerTask =
11                     getBitmapWorkerTask(imageView);
12             if (this == bitmapWorkerTask && imageView != null) {
13                 imageView.setImageBitmap(bitmap);
14             }
15         }
16     }
17 }

By the above method, you can ListView, GridView or other assembly having a sub-view of recycling. Calling

loadBitmap you can simply add pictures to the ImageView, such as: getView method GirdView the Adapter in the call.

Reproduced in: https: //my.oschina.net/weisenz/blog/200654

Guess you like

Origin blog.csdn.net/weixin_34236497/article/details/91920884