Processing Bitmaps Off the UI Thread
来源:互联网 发布:调查问卷 代码java 编辑:程序博客网 时间:2024/05/20 13:19
在高效地加载Bitmap中,讨论了BitmapFactory.decode*系列方法,如果图片的源数据来自硬盘或者网络(或者其他非内存的来源),是不应该在UI线程中执行的。这是因为加载这样的数据所需的时间是不确定的,它依赖于多个因素(从硬盘或网络的读取速度、图片的大小、CPU的功率等等)。如果这些任务里面任何一个阻塞了UI线程,系统会将你的应用标记为未响应,并且用户可以选择关闭应用(更多信息,请参阅Designing for Responsiveness)。
这节课将教会你使用AsyncTask在后台线程处理Bitmap并向你展示如何处理并发问题。
使用AsyncTask(异步任务)
AsyncTask类提供了一种简单的方法,可以在后台线程处理一些事情,并将结果返回到UI线程。要使用它,需要创建一个它的子类,并且覆写它提供的方法。下面是一个使用AsyncTask和decodeSampledBitmapFromResource()加载大图片到ImageView中的例子:01
class
BitmapWorkerTask
extends
AsyncTask<Integer, Void, Bitmap> {
02
private
final
WeakReference<ImageView> imageViewReference;
03
private
int
data =
0
;
04
05
public
BitmapWorkerTask(ImageView imageView) {
06
// Use a WeakReference to ensure the ImageView can be garbage collected
07
imageViewReference =
new
WeakReference<ImageView>(imageView);
08
}
09
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
}
ImageView的WeakReference(弱引用)可以确保AsyncTask不会阻止ImageView和它的任何引用被垃圾回收器回收。不能保证在异步任务完成后ImageView依然存在,因此你必须在onPostExecute()方法中检查引用。ImageView可能已经不存在了,比如说,用户在任务完成前退出了当前Activity或者应用配置发生了变化(横屏)。
为了异步加载Bitmap,我们创建一个简单的异步任务并且执行它:
1
public
void
loadBitmap(
int
resId, ImageView imageView) {
2
BitmapWorkerTask task =
new
BitmapWorkerTask(imageView);
3
task.execute(resId);
4
}
处理并发
常见的View(视图)组件如ListView和GridView在于AsyncTask配合使用的时候引出了另外一个问题,这个我们在上一节中提到过。为了提升内存效率,当用户滚动这些组件的时候进行子视图的回收(主要是回收不可见的视图)。如果每个子视图都触发了一个AsyncTask,无法保证在任务完成的时候,关联视图还没有被回收而被用来显示另一个子视图。此外,也无法保证异步任务结束的循序与它们开始的顺序一致。
Multithreading for Performance这篇文章深入讨论了如何处理并发问题,并且给出了如何在任务结束的时候检测ImageView存储最近使用的AsyncTask引用的解决方案。使用相似的方法,可以遵循类似的模式来扩展前面的AsyncTask。
创建一个专用的Drawable之类,用来存储worker task的引用。在这种情况下,任务结束的时候BitmapDrawable可以取代图像占位符显示在ImageView中。
01
static
class
AsyncDrawable
extends
BitmapDrawable {
02
private
final
WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
03
04
public
AsyncDrawable(Resources res, Bitmap bitmap,
05
BitmapWorkerTask bitmapWorkerTask) {
06
super
(res, bitmap);
07
bitmapWorkerTaskReference =
08
new
WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
09
}
10
11
public
BitmapWorkerTask getBitmapWorkerTask() {
12
return
bitmapWorkerTaskReference.get();
13
}
14
}
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
}
01
public
static
boolean
cancelPotentialWork(
int
data, ImageView imageView) {
02
final
BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
03
04
if
(bitmapWorkerTask !=
null
) {
05
final
int
bitmapData = bitmapWorkerTask.data;
06
if
(bitmapData != data) {
07
// Cancel previous task
08
bitmapWorkerTask.cancel(
true
);
09
}
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
}
一个助手方法,getBitmapWorkerTask(),在上面用来检索和指定ImageView相关的任务
01
private
static
BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
02
if
(imageView !=
null
) {
03
final
Drawable drawable = imageView.getDrawable();
04
if
(drawable
instanceof
AsyncDrawable) {
05
final
AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
06
return
asyncDrawable.getBitmapWorkerTask();
07
}
08
}
09
return
null
;
10
}
01
class
BitmapWorkerTask
extends
AsyncTask<Integer, Void, Bitmap> {
02
...
03
04
@Override
05
protected
void
onPostExecute(Bitmap bitmap) {
06
if
(isCancelled()) {
07
bitmap =
null
;
08
}
09
10
if
(imageViewReference !=
null
&& bitmap !=
null
) {
11
final
ImageView imageView = imageViewReference.get();
12
final
BitmapWorkerTask bitmapWorkerTask =
13
getBitmapWorkerTask(imageView);
14
if
(
this
== bitmapWorkerTask && imageView !=
null
) {
15
imageView.setImageBitmap(bitmap);
16
}
17
}
18
}
19
}
- 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]
- 制做jffs2文件系统
- 你可能不知道的Shell
- OGNL技术讲解
- JSP页面常用总结1
- ZOJ 1576(稳定婚姻系统-重名)
- Processing Bitmaps Off the UI Thread
- AddressBook.Framework应用之ABAddressBookRef,ABRecordRef,ABMutableMultiValueRef,ABMultiValueRef
- java生成二维码
- kmp算法源码-经过比较,这个源码的速度应该是移动最快的。
- 主键并非是一个字段,也可以是多个字段。
- ibus for centOS
- 挂载nfs文件系统
- 构建 Linux 文件系统
- Java多线程详解