Processing Bitmaps Off the UI Thread
来源:互联网 发布:编程猫的网址 编辑:程序博客网 时间:2024/05/20 13:14
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.
译:
在上一课中有介绍一系列的BitmapFactory.decode*) 方法,当数据源是网络或者是磁盘时(或者是任何实际源不在内存的),这些方法都不应该在main UI 线程中执行。那些情况下加载数据是不可以预知的,它依赖于许多因素(从网络或者硬盘读取数据的速度, 图片的大小, CPU的速度, etc.)。如果其中任何一个任务卡住了UI thread, 系统会出现ANR的错误。
这一节课会介绍如何使用 AsyncTask 在后台线程中处理bitmap并且演示了如何处理并发(concurrency)的问题。
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()
:
译:
AsyncTask 类提供了一个简单的方法来在后台线程执行一些操作,并且可以把后台的结果呈现到UI线程。下面是一个加载大图的示例:
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()
. TheImageView
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:
译:
为ImageView使用WeakReference 确保了 AsyncTask 所引用的资源可以被GC(garbage collected)。因为当任务结束时不能确保 ImageView 仍然存在,因此你必须在 onPostExecute() 里面去检查引用。这个ImageView 也许已经不存在了,例如,在任务结束时用户已经不在那个Activity或者是设备已经发生配置改变(旋转屏幕等)。
开始异步加载位图,只需要创建一个新的任务并执行它即可:
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.
译:Multithreading for Performance 这篇博文更进一步的讨论了如何处理并发并且提供了一种解决方法,当任务结束时ImageView 保存一个最近常使用的AsyncTask引用。使用类似的方法, AsyncTask 可以扩展出一个类似的模型。创建一个专用的 Drawable 子类来保存一个可以回到当前工作任务的引用。在这种情况下,BitmapDrawable 被用来作为占位图片,它可以在任务结束时显示到ImageView中。
注:上面的翻译始终感觉很挫。还是看英文吧。
Create a dedicated Drawable
subclass to store a reference back to the worker task. In this case, aBitmapDrawable
is used so that a placeholder image can be displayed in the ImageView
while the task completes:
译:
创建一个专用的Drawable的子类来储存返回工作任务的引用。在这种情况下,当任务完成时BitmapDrawable会被使用,placeholder image才会在ImageView中被显示:
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 targetImageView
:
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 callingcancel()
. 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
;
}
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.
译:
这个方法不仅仅适用于 ListView 与 GridView 组件,在那些需要循环利用子视图的组件中同样适用。只需要在设置图片到ImageView的地方调用 loadBitmap
方法。例如,在GridView 中实现这个方法会是在 getView() 方法里面调用。
- 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]
- Masonry介绍与使用实践:快速上手Autolayout
- web 跨域请求共享资源(OCRS)
- 商场促销-策略模式
- MyEclipse 6.5 配置 Tomcat7
- 分治法和动态规划法解最大子序列问题 C++
- Processing Bitmaps Off the UI Thread
- linux期末复习知识点小结(一)——Introduction
- 设计模式(五)适配器
- 【Jenkins系列之一】Jenkins持续集成环境搭建完全指南
- MFC中获取各个窗口(对话框)之间的指针、对象、句柄
- Caching Bitmaps
- bzoj 2761 题解
- Domino Calendar REST API性能调优 之 代码篇
- Android中试调程序debug