UI显示Bitmap整合前两章内容
来源:互联网 发布:c语言视频下载 编辑:程序博客网 时间:2024/06/06 02:29
转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)
http://my.oschina.net/ryanhoo/blog/88484
译者:Ryan Hoo
来源:https://developer.android.com/develop/index.html
译者按: 在Google最新的文档中,提供了一系列含金量相当高的教程。因为种种原因而鲜为人知,真是可惜!Ryan将会细心整理,将之翻译成中文,希望对开发者有所帮助。
本系列是Google关于展示大Bitmap(位图)的官方演示,可以有效的解决内存限制,更加有效的加载并显示图片,同时避免让人头疼的OOM(Out Of Memory)。
-------------------------------------------------------------------------------------
译文:
这节课将我们前面几节课学习的东西都整合起来,向你展示如何使用后台线程和Bitmap缓存加载多个Bitmap(位图)到ViewPager和GridView组件中,并学习如何处理并发和配置变化问题。
实现加载Bitmap到ViewPager滑动浏览模式(Swipe View Pattern)是一种很好的浏览详细图片的方式。你可以使用ViewPager组件配合PagerAdapter(适配器)来实现这种模式。然而,更加合适的适配器是FragmentStatePagerAdapter,它可以在ViewPager退出屏幕的时候自动销毁并存储Fragments的状态,使得内存依然保留下来。
注意:如果你只有少量的图片,并且确信它们不会超出程序的内存限制,使用常规的PagerAdapter或者FragmentPagerAdapter或许更加合适。
这里有一个包含ImageView的ViewPager的实现类,Main Activity(主活动)持有这个ViewPager和Adapter。
01
public
class
ImageDetailActivity
extends
FragmentActivity {
02
public
static
final
String EXTRA_IMAGE =
"extra_image"
;
03
04
private
ImagePagerAdapter mAdapter;
05
private
ViewPager mPager;
06
07
// A static dataset to back the ViewPager adapter
08
public
final
static
Integer[] imageResIds =
new
Integer[] {
09
R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
10
R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
11
R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
12
13
@Override
14
public
void
onCreate(Bundle savedInstanceState) {
15
super
.onCreate(savedInstanceState);
16
setContentView(R.layout.image_detail_pager);
// Contains just a ViewPager
17
18
mAdapter =
new
ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);
19
mPager = (ViewPager) findViewById(R.id.pager);
20
mPager.setAdapter(mAdapter);
21
}
22
23
public
static
class
ImagePagerAdapter
extends
FragmentStatePagerAdapter {
24
private
final
int
mSize;
25
26
public
ImagePagerAdapter(FragmentManager fm,
int
size) {
27
super
(fm);
28
mSize = size;
29
}
30
31
@Override
32
public
int
getCount() {
33
return
mSize;
34
}
35
36
@Override
37
public
Fragment getItem(
int
position) {
38
return
ImageDetailFragment.newInstance(position);
39
}
40
}
41
}
这里有一个用来持有ImageView并显示详细信息的Fragment的实现类。看起来这似乎是非常合理的方法,但是你能否看到这个方案的缺点呢?应该如何改善它呢?
01
public
class
ImageDetailFragment
extends
Fragment {
02
private
static
final
String IMAGE_DATA_EXTRA =
"resId"
;
03
private
int
mImageNum;
04
private
ImageView mImageView;
05
06
static
ImageDetailFragment newInstance(
int
imageNum) {
07
final
ImageDetailFragment f =
new
ImageDetailFragment();
08
final
Bundle args =
new
Bundle();
09
args.putInt(IMAGE_DATA_EXTRA, imageNum);
10
f.setArguments(args);
11
return
f;
12
}
13
14
// Empty constructor, required as per Fragment docs
15
public
ImageDetailFragment() {}
16
17
@Override
18
public
void
onCreate(Bundle savedInstanceState) {
19
super
.onCreate(savedInstanceState);
20
mImageNum = getArguments() !=
null
? getArguments().getInt(IMAGE_DATA_EXTRA) : -
1
;
21
}
22
23
@Override
24
public
View onCreateView(LayoutInflater inflater, ViewGroup container,
25
Bundle savedInstanceState) {
26
// image_detail_fragment.xml contains just an ImageView
27
final
View v = inflater.inflate(R.layout.image_detail_fragment, container,
false
);
28
mImageView = (ImageView) v.findViewById(R.id.imageView);
29
return
v;
30
}
31
32
@Override
33
public
void
onActivityCreated(Bundle savedInstanceState) {
34
super
.onActivityCreated(savedInstanceState);
35
final
int
resId = ImageDetailActivity.imageResIds[mImageNum];
36
mImageView.setImageResource(resId);
// Load image into ImageView
37
}
38
}
希望你能注意到:这些图片是在UI线程从资源中读取过来的,而这极有可能导致应用挂起甚至被强制关闭。使用在“非UI线程处理Bitmap”一课中提到的AsyncTask,直接将图片加载和处理移到后台线程中。
任何额外的处理(例如调整大小或者从网络获取图片)可以放在BitmapWorkerTask中而不会影响到主UI线程的响应性。如果后台线程做的不仅仅是直接从硬盘直接加载图片,那么如“缓存Bitmap”一课中说的,将图片缓存到内存或者硬盘是有利于程序优化的。这里是对内存缓存的一些额外修改:
01
public
class
ImageDetailActivity
extends
FragmentActivity {
02
...
03
private
LruCache<String, Bitmap> mMemoryCache;
04
05
@Override
06
public
void
onCreate(Bundle savedInstanceState) {
07
...
08
// initialize LruCache as per Use a Memory Cache section
09
}
10
11
public
void
loadBitmap(
int
resId, ImageView imageView) {
12
final
String imageKey = String.valueOf(resId);
13
14
final
Bitmap bitmap = mMemoryCache.get(imageKey);
15
if
(bitmap !=
null
) {
16
mImageView.setImageBitmap(bitmap);
17
}
else
{
18
mImageView.setImageResource(R.drawable.image_placeholder);
19
BitmapWorkerTask task =
new
BitmapWorkerTask(mImageView);
20
task.execute(resId);
21
}
22
}
23
24
...
// include updated BitmapWorkerTask from Use a Memory Cache section
25
}
将上面的代码片段整合在一起会让你的ViewPager具备优良的响应性能,可以实现最小的加载延迟,根据你的图片加载需要或多或少的进行后台处理。
实现加载Bitmap到GridView
网格列表控件(Grid List Building Block)对于显示图片数据集非常有用,也可以使用GridView组件来实现,如果用户上下滚动的话,有很多图片处于就绪状态,随时可以显示在屏幕上。如果要实现这种类型的控制,你必须确保UI保持流畅性,内存使用处于控制之中而且并发也要被正确地处理(取决于GridView回收子视图的方式)。
首先,这里有一个标准的GridView实现,将ImageView子控件存放在Fragment中。我们再一次思考这个问题,这个方法看起来似乎非常完美且合乎情理,但是有没有办法让它便得更好呢?
01
public
class
ImageGridFragment
extends
Fragment
implements
AdapterView.OnItemClickListener {
02
private
ImageAdapter mAdapter;
03
04
// A static dataset to back the GridView adapter
05
public
final
static
Integer[] imageResIds =
new
Integer[] {
06
R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
07
R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
08
R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
09
10
// Empty constructor as per Fragment docs
11
public
ImageGridFragment() {}
12
13
@Override
14
public
void
onCreate(Bundle savedInstanceState) {
15
super
.onCreate(savedInstanceState);
16
mAdapter =
new
ImageAdapter(getActivity());
17
}
18
19
@Override
20
public
View onCreateView(
21
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
22
final
View v = inflater.inflate(R.layout.image_grid_fragment, container,
false
);
23
final
GridView mGridView = (GridView) v.findViewById(R.id.gridView);
24
mGridView.setAdapter(mAdapter);
25
mGridView.setOnItemClickListener(
this
);
26
return
v;
27
}
28
29
@Override
30
public
void
onItemClick(AdapterView<?> parent, View v,
int
position,
long
id) {
31
final
Intent i =
new
Intent(getActivity(), ImageDetailActivity.
class
);
32
i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);
33
startActivity(i);
34
}
35
36
private
class
ImageAdapter
extends
BaseAdapter {
37
private
final
Context mContext;
38
39
public
ImageAdapter(Context context) {
40
super
();
41
mContext = context;
42
}
43
44
@Override
45
public
int
getCount() {
46
return
imageResIds.length;
47
}
48
49
@Override
50
public
Object getItem(
int
position) {
51
return
imageResIds[position];
52
}
53
54
@Override
55
public
long
getItemId(
int
position) {
56
return
position;
57
}
58
59
@Override
60
public
View getView(
int
position, View convertView, ViewGroup container) {
61
ImageView imageView;
62
if
(convertView ==
null
) {
// if it's not recycled, initialize some attributes
63
imageView =
new
ImageView(mContext);
64
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
65
imageView.setLayoutParams(
new
GridView.LayoutParams(
66
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
67
}
else
{
68
imageView = (ImageView) convertView;
69
}
70
imageView.setImageResource(imageResIds[position]);
// Load image into ImageView
71
return
imageView;
72
}
73
}
74
}
当然,问题还是这个方法在UI线程中处理图片。这种方式或许是和处理小而简单的图片(系统资源的加载和缓存),如果需要做任何的处理,UI就会被阻塞(甚至引起ANR(Application Not Responding))。
和前一节相同的处理方式,我们在异步线程中进行处理和缓存。然而,考虑到GridView回收子视图的方式,你需要谨慎处理并发问题。可以使用“在非UI线程中处理Bitmap”一课中提到的技巧。这里是更新的解决方案:
01
public
class
ImageGridFragment
extends
Fragment
implements
AdapterView.OnItemClickListener {
02
...
03
04
private
class
ImageAdapter
extends
BaseAdapter {
05
...
06
07
@Override
08
public
View getView(
int
position, View convertView, ViewGroup container) {
09
...
10
loadBitmap(imageResIds[position], imageView)
11
return
imageView;
12
}
13
}
14
15
public
void
loadBitmap(
int
resId, ImageView imageView) {
16
if
(cancelPotentialWork(resId, imageView)) {
17
final
BitmapWorkerTask task =
new
BitmapWorkerTask(imageView);
18
final
AsyncDrawable asyncDrawable =
19
new
AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
20
imageView.setImageDrawable(asyncDrawable);
21
task.execute(resId);
22
}
23
}
24
25
static
class
AsyncDrawable
extends
BitmapDrawable {
26
private
final
WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
27
28
public
AsyncDrawable(Resources res, Bitmap bitmap,
29
BitmapWorkerTask bitmapWorkerTask) {
30
super
(res, bitmap);
31
bitmapWorkerTaskReference =
32
new
WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
33
}
34
35
public
BitmapWorkerTask getBitmapWorkerTask() {
36
return
bitmapWorkerTaskReference.get();
37
}
38
}
39
40
public
static
boolean
cancelPotentialWork(
int
data, ImageView imageView) {
41
final
BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
42
43
if
(bitmapWorkerTask !=
null
) {
44
final
int
bitmapData = bitmapWorkerTask.data;
45
if
(bitmapData != data) {
46
// Cancel previous task
47
bitmapWorkerTask.cancel(
true
);
48
}
else
{
49
// The same work is already in progress
50
return
false
;
51
}
52
}
53
// No task associated with the ImageView, or an existing task was cancelled
54
return
true
;
55
}
56
57
private
static
BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
58
if
(imageView !=
null
) {
59
final
Drawable drawable = imageView.getDrawable();
60
if
(drawable
instanceof
AsyncDrawable) {
61
final
AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
62
return
asyncDrawable.getBitmapWorkerTask();
63
}
64
}
65
return
null
;
66
}
67
68
...
// include updated BitmapWorkerTask class
注意:相同的代码也可以很好的适配ListView。
这里的实现方法允许灵活地处理和加载图片,并且不会影响UI的流畅性。在后台线程中,你可以从网络加载图片,调整大幅的数码相机照片的大小,并在处理任务结束的时候将图片显示在UI界面中。
要了解在本节课中讨论到的概念和完整代码,请参阅示例程序。
BitmapFun:http://vdisk.weibo.com/s/hNgFB
- UI显示Bitmap整合前两章内容
- 在UI中显示Bitmap
- 在UI中显示Bitmap
- 在UI中显示Bitmap
- 在UI上显示Bitmap
- 第四课:在UI中显示Bitmap
- android 在UI上显示Bitmap
- 高效显示Bitmap之UI线程外处理Bitmap
- Displaying Bitmaps in Your UI 在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 【Google官方教程】第四课:在UI中显示Bitmap
- 高效显示Bitmap2--->非UI线程处理Bitmap
- 文本相似度——编辑距离算法&java简单实现
- unity3d 从0开始学
- Android编译之MAKE
- 浏览器发送URL的编码特性
- 带指针参数的函数指针数组
- UI显示Bitmap整合前两章内容
- 设计模式之简单模式与策略模式
- ActiveMQ的消息重试机制
- 广义线性模型之logistic regression(二)
- struts1与struts2的区别
- Python print函数用法,print 格式化输出(python格式化输出)
- 9.文件与文件系统的压缩与打包
- lua语法
- 大神博客