Processing Bitmaps Off the UI Thread
来源:互联网 发布:淘宝按那张图辨别同款 编辑:程序博客网 时间:2024/05/20 13:19
From: http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
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 using AsyncTask and shows you how to handle concurrency issues.
Use an 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<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(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 the AsyncTask 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.
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);
}
Handle Concurrency
Common view components such as ListView and GridView introduce another issue when used in conjunction with the AsyncTask as demonstrated in the previous section. In order to be efficient with memory, these components recycle child views as the user scrolls. If each child view triggers an AsyncTask, there is no guarantee that when it completes, the associated view has not already been recycled for use in another child view. Furthermore, there is no guarantee that the order in which asynchronous tasks are started is the order that they complete.
The blog post Multithreading for Performance further discusses dealing with concurrency, and offers a solution where the ImageView stores a reference to the most recent AsyncTask which can later be checked when the task completes. Using a similar method, the AsyncTask from the previous section can be extended to follow a similar pattern.
Create a dedicated Drawable subclass to store a reference back to the worker task. In this case, a BitmapDrawable is used so that a placeholder image can be displayed in the ImageView while the task completes:
static class AsyncDrawable extends BitmapDrawable {
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
public AsyncDrawable(Resources res, Bitmap bitmap,
BitmapWorkerTask bitmapWorkerTask) {
super(res, bitmap);
bitmapWorkerTaskReference =
new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
}
public BitmapWorkerTask getBitmapWorkerTask() {
return bitmapWorkerTaskReference.get();
}
}
Before executing the BitmapWorkerTask, you create an AsyncDrawable and bind it to the target ImageView:
public void loadBitmap(int resId, ImageView imageView) {
if (cancelPotentialWork(resId, imageView)) {
final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
final AsyncDrawable asyncDrawable =
new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
imageView.setImageDrawable(asyncDrawable);
task.execute(resId);
}
}
The cancelPotentialWork method referenced in the code sample above checks if another running task is already associated with the ImageView. If so, it attempts to cancel the previous task by calling cancel(). In a small number of cases, the new task data matches the existing task and nothing further needs to happen. Here is the implementation of cancelPotentialWork:
public static boolean cancelPotentialWork(int data, ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (bitmapWorkerTask != null) {
final int bitmapData = bitmapWorkerTask.data;
// If bitmapData is not yet set or it differs from the new data
if (bitmapData == 0 || bitmapData != data) {
// Cancel previous task
bitmapWorkerTask.cancel(true);
} else {
// The same work is already in progress
return false;
}
}
// No task associated with the ImageView, or an existing task was cancelled
return true;
}
A helper method, getBitmapWorkerTask(), is used above to retrieve the task associated with a particular ImageView:
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
return asyncDrawable.getBitmapWorkerTask();
}
}
return null;
}
The last step is updating onPostExecute() in BitmapWorkerTask so that it checks if the task is cancelled and if the current task matches the one associated with the ImageView:
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
...
@Override
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
final BitmapWorkerTask bitmapWorkerTask =
getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask && imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
This implementation is now suitable for use in ListView and GridView components as well as any other components that recycle their child views. Simply call loadBitmap where you normally set an image to your ImageView. For example, in a GridView implementation this would be in the getView() method of the backing adapter.
0 0
- Processing Bitmaps Off the UI Thread
- Processing Bitmaps Off the UI Thread
- Processing Bitmaps Off the UI Thread
- Processing Bitmaps Off the UI Thread
- Processing Bitmaps Off the UI Thread
- Displaying Bitmaps Efficiently(2)-Processing Bitmaps Off the UI Thread
- Displaying Bitmaps Efficiently - Processing Bitmaps Off the UI Thread
- Displaying Bitmaps Efficiently (二)-----Processing Bitmaps Off the UI Thread
- Displaying Bitmaps Efficiently之Processing Bitmaps Off the UI Thread
- [Developer Android] Processing Bitmaps Off the UI Thread
- Processing Bitmaps Off the UI Thread [在非UI线程处理Bitmap]
- Processing Bitmaps Off the UI Thread 处理来自UI线程的位图
- Processing Bitmaps Off the UI Thread [在UI 线程之外处理Bitmap]
- Processing Bitmaps Off the UI Thread(处理UI线程的位图)
- 3 Processing Bitmaps Off the UI Thread(处理UI线程的位图)
- Processing Bitmaps Off the UI Thread不在UI线程中处理Bitmaps(Android官方翻译文档2)
- Android 有效地展示图片(二)Processing Bitmaps Off the UI Thread 在ui线程外处理bitmap
- Displaying Bitmaps in Your UI [ 在UI中显示Bitmaps]
- java思想总结6---容器(一)
- xgtfhdrfgsertrdytfutyuyt
- zfddhdg在电饭锅电话太符合
- Ubuntu配置文件/etc/profile说明
- 中国1月CPI同比增长0.8% 5年首次跌破1%
- Processing Bitmaps Off the UI Thread
- 工作杂谈:产品经理的工作职责
- 因子和因子个数
- Javascript 链式运动框架——逐行分析代码,让你轻松了解运动的原理
- Java异常处理(附常见的异常)
- 6 Python Performance Tips
- IOS支付宝SDK跳转wap支付不成功
- 同样的MVC,不同的实现方法(Spring MVC .Net MVC)
- 文本流和二进制流