Displaying Bitmaps in Your UI
来源:互联网 发布:编程猫的网址 编辑:程序博客网 时间:2024/05/19 02:45
This lesson brings together everything from previous lessons, showing you how to load multiple bitmaps intoViewPager
and GridView
components using a background thread and bitmap cache, while dealing with concurrency and configuration changes.
Load Bitmaps into a ViewPager Implementation
The swipe view pattern is an excellent way to navigate the detail view of an image gallery. You can implement this pattern using a ViewPager
component backed by aPagerAdapter
. However, a more suitable backing adapter is the subclass FragmentStatePagerAdapter
which automatically destroys and saves state of the Fragments
in the ViewPager
as they disappear off-screen, keeping memory usage down.
Note: If you have a smaller number of images and are confident they all fit within the application memory limit, then using a regular PagerAdapter
orFragmentPagerAdapter
might be more appropriate.
Here’s an implementation of a ViewPager
with ImageView
children. The main activity holds theViewPager
and the adapter:
译:
这一课会演示如何运用前面几节课的内容,使用后台线程与Cache机制来加载图片到 ViewPager 与 GridView 组件,并且学习处理并发与配置改变问题。
实现加载图片到ViewPager(Load Bitmaps into a ViewPager Implementation)
swipe view pattern是一个用来切换显示不同详情界面的很好的方法。(关于这种效果请先参看Android Design: Swipe Views).
你可以通过 PagerAdapter 与 ViewPager 组件来实现这个效果。 然而,一个更加合适的Adapter是PagerAdapter 的子类 FragmentStatePagerAdapter:它可以在某个ViewPager中的子视图切换出屏幕时自动销毁与保存 Fragments 的状态。这样能够保持消耗更少的内存。
Note: 如果你只有为数不多的图片并且确保不会超出程序内存限制,那么使用 PagerAdapter 或 FragmentPagerAdapter 会更加合适。
下面是一个使用ViewPager与ImageView作为子视图的示例。主Activity包含有ViewPager 和adapter。
public
class
ImageDetailActivity
extends
FragmentActivity {
public
static
final
String EXTRA_IMAGE =
"extra_image"
;
private
ImagePagerAdapter mAdapter;
private
ViewPager mPager;
// A static dataset to back the ViewPager adapter
public
final
static
Integer[] imageResIds =
new
Integer[] {
R.drawable.sample_image_1, R.drawable.sample_image_2, R.drawable.sample_image_3,
R.drawable.sample_image_4, R.drawable.sample_image_5, R.drawable.sample_image_6,
R.drawable.sample_image_7, R.drawable.sample_image_8, R.drawable.sample_image_9};
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.image_detail_pager);
// Contains just a ViewPager
mAdapter =
new
ImagePagerAdapter(getSupportFragmentManager(), imageResIds.length);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
public
static
class
ImagePagerAdapter
extends
FragmentStatePagerAdapter {
private
final
int
mSize;
public
ImagePagerAdapter(FragmentManager fm,
int
size) {
super
(fm);
mSize = size;
}
@Override
public
int
getCount() {
return
mSize;
}
@Override
public
Fragment getItem(
int
position) {
return
ImageDetailFragment.newInstance(position);
}
}
}
Here is an implementation of the details Fragment
which holds the ImageView
children. This might seem like a perfectly reasonable approach, but can you see the drawbacks of this implementation? How could it be improved?
public
class
ImageDetailFragment
extends
Fragment {
private
static
final
String IMAGE_DATA_EXTRA =
"resId"
;
private
int
mImageNum;
private
ImageView mImageView;
static
ImageDetailFragment newInstance(
int
imageNum) {
final
ImageDetailFragment f =
new
ImageDetailFragment();
final
Bundle args =
new
Bundle();
args.putInt(IMAGE_DATA_EXTRA, imageNum);
f.setArguments(args);
return
f;
}
// Empty constructor, required as per Fragment docs
public
ImageDetailFragment() {}
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
mImageNum = getArguments() !=
null
? getArguments().getInt(IMAGE_DATA_EXTRA) : -
1
;
}
@Override
public
View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// image_detail_fragment.xml contains just an ImageView
final
View v = inflater.inflate(R.layout.image_detail_fragment, container,
false
);
mImageView = (ImageView) v.findViewById(R.id.imageView);
return
v;
}
@Override
public
void
onActivityCreated(Bundle savedInstanceState) {
super
.onActivityCreated(savedInstanceState);
final
int
resId = ImageDetailActivity.imageResIds[mImageNum];
<strong>mImageView.setImageResource(resId);</strong>
// Load image into ImageView
}
}
Hopefully you noticed the issue: the images are being read from resources on the UI thread, which can lead to an application hanging and being force closed. Using an AsyncTask
as described in theProcessing Bitmaps Off the UI Thread lesson, it’s straightforward to move image loading and processing to a background thread:
public
class
ImageDetailActivity
extends
FragmentActivity {
...
public
void
loadBitmap(
int
resId, ImageView imageView) {
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task =
new
BitmapWorkerTask(mImageView);
task.execute(resId);
}
...
// include <a href="file:///D:/Users/Administrator/AppData/Local/Android/sdk/docs/training/displaying-bitmaps/process-bitmap.html#BitmapWorkerTask"><code>BitmapWorkerTask</code></a> class
}
public
class
ImageDetailFragment
extends
Fragment {
...
@Override
public
void
onActivityCreated(Bundle savedInstanceState) {
super
.onActivityCreated(savedInstanceState);
if
(ImageDetailActivity.
class
.isInstance(getActivity())) {
final
int
resId = ImageDetailActivity.imageResIds[mImageNum];
// Call out to ImageDetailActivity to load the bitmap in a background thread
((ImageDetailActivity) getActivity()).loadBitmap(resId, mImageView);
}
}
}
Any additional processing (such as resizing or fetching images from the network) can take place in the BitmapWorkerTask
without affecting responsiveness of the main UI. If the background thread is doing more than just loading an image directly from disk, it can also be beneficial to add a memory and/or disk cache as described in the lesson Caching Bitmaps. Here’s the additional modifications for a memory cache:
public
class
ImageDetailActivity
extends
FragmentActivity {
...
private
LruCache<String, Bitmap> mMemoryCache;
@Override
public
void
onCreate(Bundle savedInstanceState) {
...
// initialize LruCache as per <a href="file:///D:/Users/Administrator/AppData/Local/Android/sdk/docs/training/displaying-bitmaps/cache-bitmap.html#memory-cache">Use a Memory Cache</a> section
}
public
void
loadBitmap(
int
resId, ImageView imageView) {
final
String imageKey = String.valueOf(resId);
final
Bitmap bitmap = mMemoryCache.get(imageKey);
if
(bitmap !=
null
) {
mImageView.setImageBitmap(bitmap);
}
else
{
mImageView.setImageResource(R.drawable.image_placeholder);
BitmapWorkerTask task =
new
BitmapWorkerTask(mImageView);
task.execute(resId);
}
}
...
// include updated BitmapWorkerTask from <a href="file:///D:/Users/Administrator/AppData/Local/Android/sdk/docs/training/displaying-bitmaps/cache-bitmap.html#memory-cache">Use a Memory Cache</a> section
}
Load Bitmaps into a GridView Implementation
The grid list building block is useful for showing image data sets and can be implemented using aGridView
component in which many images can be on-screen at any one time and many more need to be ready to appear if the user scrolls up or down. When implementing this type of control, you must ensure the UI remains fluid, memory usage remains under control and concurrency is handled correctly (due to the way GridView
recycles its children views).
To start with, here is a standard GridView
implementation with ImageView
children placed inside aFragment
. Again, this might seem like a perfectly reasonable approach, but what would make it better?
译:
Grid list building block 是一种有效显示大量图片的方式。这样能够一次显示许多图片,而且那些即将被显示的图片也处于准备显示状态。如果你想要实现这种效果,你必须确保UI是流畅的,能够控制内存使用,并且正确的处理并发问题(因为 GridView 会循环使用子视图)。
下面是一个在Fragment里面内置了ImageView作为GridView子视图的示例:
Once again, the problem with this implementation is that the image is being set in the UI thread. While this may work for small, simple images (due to system resource loading and caching), if any additional processing needs to be done, your UI grinds to a halt.
The same asynchronous processing and caching methods from the previous section can be implemented here. However, you also need to wary of concurrency issues as the GridView
recycles its children views. To handle this, use the techniques discussed in the Processing Bitmaps Off the UI Threadlesson. Here is the updated solution:
译:
又一次,这一个实现的问题是图片是在UI线程中被设置。当处理小的图片时可以,但其他需要额外操作的处理,都会使你的UI慢下来。
与前面加载到图片到ViewPager一样,如果setImageResource的操作会比较耗时,有可能会卡到UI Thread。可以使用类似前面异步处理图片与增加缓存的方法来解决那个问题。然而,我们还需要考虑GridView的循环机制所带来的并发问题。为了处理这个问题,请参考前面的课程 。下面是一个更新的解决方案:
public
class
ImageGridFragment
extends
Fragment
implements
AdapterView.OnItemClickListener {
...
private
class
ImageAdapter
extends
BaseAdapter {
...
@Override
public
View getView(
int
position, View convertView, ViewGroup container) {
...
<strong>loadBitmap(imageResIds[position], imageView)</strong>
return
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);
}
}
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();
}
}
public
static
boolean
cancelPotentialWork(
int
data, ImageView imageView) {
final
BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if
(bitmapWorkerTask !=
null
) {
final
int
bitmapData = bitmapWorkerTask.data;
if
(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
;
}
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
;
}
...
// include updated <a href="file:///D:/Users/Administrator/AppData/Local/Android/sdk/docs/training/displaying-bitmaps/process-bitmap.html#BitmapWorkerTaskUpdated"><code>BitmapWorkerTask</code></a> class
Note: The same code can easily be adapted to work with ListView
as well.
This implementation allows for flexibility in how the images are processed and loaded without impeding the smoothness of the UI. In the background task you can load images from the network or resize large digital camera photos and the images appear as the tasks finish processing.
For a full example of this and other concepts discussed in this lesson, please see the included sample application.
- Displaying Bitmaps in Your UI
- Displaying Bitmaps in Your UI
- Displaying Bitmaps Efficiently之Displaying Bitmaps in Your UI
- Displaying Bitmaps in Your UI [ 在UI中显示Bitmaps]
- Displaying Bitmaps in Your UI 在UI中显示Bitmap
- Displaying Bitmaps in Your UI[在UI上呈现Bitmap]
- Displaying Bitmaps in Your UI 在你的UI显示位图
- Displaying Bitmaps in Your UI在你的UI上展示Bitmaps(Android官方文档翻译——五)
- 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
- Displaying Bitmaps Efficiently
- Displaying Bitmaps Efficiently
- Displaying Bitmaps Efficiently
- Displaying Bitmaps Efficiently
- Displaying Bitmaps Efficiently
- Displaying Bitmaps Efficiently
- Android中试调程序debug
- GPT分区数据格式分析(图已补上)
- Managing Bitmap Memory
- 富文本编辑
- 《征服C指针》读后笔记
- Displaying Bitmaps in Your UI
- myeclispe 中deploy时不能出现deploy location?
- 由观察者模式的升级,得出委托代理
- SMP与Cluster的比较
- UVA File Fragmentation(文件复原)
- 导入cvs文件的方法
- 小怪物重制计划第六天
- MySql 问题解决整理
- Displaying Bitmap小结