The BitmapFactory.decode*
methods, discussed in the Load Large Bitmaps Efficiently lesson, should not be executed on the main UI thread if the source data is read from disk or a network location (or really any source other than memory). The time this data takes to load is unpredictable and depends on a variety of factors (speed of reading from disk or network, size of image, power of CPU, etc.). If one of these tasks blocks the UI thread, the system flags your application as non-responsive and the user has the option of closing it (see Designing for Responsiveness for more information).
This lesson walks you through processing bitmaps in a background thread usingAsyncTask
and shows you how to handle concurrency issues.
为防止从disk或network获取数据时延迟导致UI线程的阻塞,我们使用AsyncTask来处理图片展示。
The AsyncTask
class provides an easy way to execute some work in a background thread and publish the results back on the UI thread. To use it, create a subclass and override the provided methods. Here’s an example of loading a large image into an ImageView
using AsyncTask
and decodeSampledBitmapFromResource()
:
class BitmapWorkerTask extends AsyncTask { private final WeakReference imageViewReference; private int data = 0; public BitmapWorkerTask(ImageView imageView) { // Use a WeakReference to ensure the ImageView can be garbage collected imageViewReference = new WeakReference(imageView); } // Decode image in background. @Override protected Bitmap doInBackground(Integer... params) { data = params[0]; return decodeSampledBitmapFromResource(getResources(), data, 100, 100)); } // Once complete, see if ImageView is still around and set bitmap. @Override protected void onPostExecute(Bitmap bitmap) { if (imageViewReference != null && bitmap != null) { final ImageView imageView = imageViewReference.get(); if (imageView != null) { imageView.setImageBitmap(bitmap); } } } }
The WeakReference
to the ImageView
ensures that theAsyncTask
does not prevent the ImageView
and anything it references from being garbage collected. There’s no guarantee the ImageView
is still around when the task finishes, so you must also check the reference in onPostExecute()
. The ImageView
may no longer exist, if for example, the user navigates away from the activity or if a configuration change happens before the task finishes.
这里使用WeakReference来持有ImageView,这样就不会阻止别的地方对ImageView对象的释放;所以当在AsyncTask中使用ImageView时我们要先判断ImageView是否为空。
To start loading the bitmap asynchronously, simply create a new task and execute it:
public void loadBitmap(int resId, ImageView imageView) { BitmapWorkerTask task = new BitmapWorkerTask(imageView); task.execute(resId); }