由于本人英文能力实在有限,不足之初敬请谅解

本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接

Displaying Bitmaps in Your UI

在你的UI中显示Bitmap

This lesson brings together everything from previous lessons, showing you how to load multiple bitmaps into ViewPager and GridView components using a background thread and bitmap cache, while dealing with concurrency and configuration changes.

这里汇总了之前课程,展示给你当处理并发和配置改变时,如何使用后台线程和bitmap缓存加载多图片到ViewPager和GridView组件中

Load Bitmaps into a ViewPager Implementation

加载bitmap到ViewPager的实现

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 a PagerAdapter.

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.

swipe view模式是一种极好的方式来导航一个图片画廊的详细视图

你可以使用ViewPager组件和PagerAdapter实现这个模式

然而,一个更适合的adapter是FragmentStatePagerAdapter,当他们消失在屏幕之外时,它可以在ViewPager中自动销毁和保存Fragment的状态,保持内存的低使用率

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 or FragmentPagerAdapter might be more appropriate.

注意:如果你有较少的图片,并且确定他们在应用内存限制之内,那么使用一个常规的PagerAdapter 或者 FragmentPagerAdapter可能更适合

Here’s an implementation of a ViewPager with ImageView children.

The main activity holds the ViewPager and the adapter:

下面是ViewPager使用ImageView做子view的实现

主activity持有ViewPager和适配器

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?

下面是F详细的ragment持有ImageView子view的实现

这似乎是完美、合理的手段,但是你能看出这种实现其中的弊端码?如何改良?

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];
mImageView.setImageResource(resId); // 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 the Processing Bitmaps Off the UI Thread lesson, it’s straightforward to move image loading and processing to a background thread:

希望你注意到了这件事:图片是在UI线程中从资源中读取的,这可导致应用冻屏并且被强制关闭

像Processing Bitmaps Off the UI Thread中那样使用AsyncTask,直接把图片加载和处理放到后台线程中:

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 BitmapWorkerTask 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:

任何额外的处理(比如改变图片大小、从网络上获取图片)在BitmapWorkerTask发生则不会影响主UI的响应

如果后台进程不止是直接从磁盘加载图片,它还可以像Caching Bitmaps中描述的添加一个内存缓存/磁盘缓存也是有益的

public class ImageDetailActivity extends FragmentActivity {
...
private LruCache<String, Bitmap> mMemoryCache; @Override
public void onCreate(Bundle savedInstanceState) {
...
// initialize LruCache as per Use a Memory Cache 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 Use a Memory Cache section
}

Putting all these pieces together gives you a responsive ViewPager implementation with minimal image loading latency and the ability to do as much or as little background processing on your images as needed.

把所有这些片断放到一起,你会得到一个响应性良好的,最小图片加载延迟的ViewPager实现,或多或少的对你的图片做一些所需的后台处理

Load Bitmaps into a GridView Implementation

加载bitmap到GridView的实现

The grid list building block is useful for showing image data sets and can be implemented using a GridView 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).

grid list building block有助于图像数据集的显示,而且可以使用gridview组件实现;用gridview控件,许多图像可以同时呈现在屏幕上,而且如果用户上下滚动鼠标,更多图像可以即时呈现

实现这种控制的时候,你必须保证你的UI保持流畅,内存使用要始终在控制之中并且正确处理并发(取决于GridView回收它的子view的方法)

To start with, here is a standard GridView implementation with ImageView children placed inside a Fragment.

Again, this might seem like a perfectly reasonable approach, but what would make it better?

这是一个标准的在Fragment使用子ImageView的GridView实现

再一次,这似乎是一个完美的合理的方法,但是如何做会更好呢?

public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
private ImageAdapter mAdapter; // A static dataset to back the GridView 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}; // Empty constructor as per Fragment docs
public ImageGridFragment() {} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new ImageAdapter(getActivity());
} @Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.image_grid_fragment, container, false);
final GridView mGridView = (GridView) v.findViewById(R.id.gridView);
mGridView.setAdapter(mAdapter);
mGridView.setOnItemClickListener(this);
return v;
} @Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);
startActivity(i);
} private class ImageAdapter extends BaseAdapter {
private final Context mContext; public ImageAdapter(Context context) {
super();
mContext = context;
} @Override
public int getCount() {
return imageResIds.length;
} @Override
public Object getItem(int position) {
return imageResIds[position];
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup container) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(imageResIds[position]); // Load image into ImageView
return imageView;
}
}
}

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.

再一次,这个实现的问题是,图片是在UI线程中设置的

也许在小且简单的图片上面可以正常工作(取决于系统资源加载和缓存),如果有任何其他过程需要完成,你的UI就会慢慢冻住

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 Thread lesson.

Here is the updated solution:

上一章节的相同的异步过程和缓存方法可以在这里实现

然后,你还是需要小心GridView回收其子view这种并发问题

为了处理这些问题,可以使用Processing Bitmaps Off the UI Thread章节中讨论的技术

下面更新一下解决方案

public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
... private class ImageAdapter extends BaseAdapter {
... @Override
public View getView(int position, View convertView, ViewGroup container) {
...
loadBitmap(imageResIds[position], imageView)
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 BitmapWorkerTask class

Note: The same code can easily be adapted to work with ListView as well.

注意:相同的代码也可以轻易的适配与ListView工作。

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.

这个实现考虑到了图片如何被处理被加载而不妨碍UI流畅性的灵活性

在后台任务中,你可以从网络或者修改大的数码相机照片大小来加载图片,当任务结束处理时,图片就显示出来。

For a full example of this and other concepts discussed in this lesson, please see the included sample application.

在这节中的完整的例子以及其他讨论过的概念,请参看样本应用

原文地址如下,英文水平实在有限,希望拍砖同时能给予指正。

http://developer.android.com/training/displaying-bitmaps/display-bitmap.html

转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

android 在你的UI中显示Bitmap - 开发文档翻译的更多相关文章

  1. android 高效显示Bitmap - 开发文档翻译

    由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接 Displaying Bitmaps Efficiently 高效显示Bitmap Lea ...

  2. android 在UI线程之外处理Bitmap - 开发文档翻译

    由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接 Processing Bitmaps Off the UI Thread 在UI线程之外处 ...

  3. ASP.NET Core 在 Swagger UI 中显示自定义的 Header Token

    Swagger 是个好东西,对于前后端分离的网站来说,不仅是提高前后端开发人员沟通效率的利器,也大大方便了后端人员测试 API.有时候,API 中可能需要在 Header 中设置认证参数,比如 aut ...

  4. 【Android Developers Training】 60. 在你的UI中显示位图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. android 在HTML中显示bitmap

    逻辑:将bitmap转化为Base64,通过调用HTML中的JS,显示到HTML中 (1)android代码 public String bitmaptoString(Bitmap bitmap) { ...

  6. 【转】引入android项目在eclipse ADT中显示中文乱码问题

    (1)修改工作空间的编码方式:Window->Preferences->General->Workspace->Text file Encoding在Others里选择需要的编 ...

  7. android 缓存Bitmap - 开发文档翻译

    由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接 Loading a single bitmap into your user interf ...

  8. Android 高级UI设计笔记17:Android在非UI线程中显示Toast

    1. 子线程的Toast怎么显示不出来? 因为Toast在创建的时候会依赖于一个Handler,并且一个Handler是需要有一个Looper才能够创建,而普通的线程是不会自动去创建一个Looper对 ...

  9. Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果

    版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/1873 ...

随机推荐

  1. C中嵌入SQL

    连接到SAMPLE数据库,查询LASTNAME为JOHNSON的FIRSTNAME信息. #include <stdio.h> #include <stdlib.h> #inc ...

  2. Java EE登陆界面生成随机数防止恶意注册或者登录

    package cn.com; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.a ...

  3. Oracle管道函数(Pipelined Table Function)介绍

    一 概述: 1.管道函数即是能够返回行集合(能够使嵌套表nested table 或数组 varray)的函数,我们能够像查询物理表一样查询它或者将其  赋值给集合变量. 2.管道函数为并行运行,在普 ...

  4. HDU 4424 Conquer a New Region 最大生成树

    给你一颗树 每条边有一个权值 选择一个点为中心 定义S值为中心到其它n-1个点的路径上的最小边权 求全部点S值的和 从大到小排序 每次合并2棵树 设为A集合 B集合 设A集合的最大S值的和为sumA ...

  5. QtWebkit中如何将网页内容转为图片

    原地址:http://www.cnblogs.com/baizx/archive/2010/07/31/1789573.html 如何将webkit中的渲染结果也就是网页画面转换为图片   用抓图软件 ...

  6. QSettings操作配置文件

    用Qt写界面时,难免会进行本地信息的保存,可以使用轻量级数据库sqlite,也可以使用QSettings读写配置文件.     如何来进行读写呢?如下,使用QSettings写一个通用的读写方法:   ...

  7. 单击Android设备后退键,主屏幕键以及旋转屏幕如何影响Activity的生命周期

    单击设备的后退键,相当于通知Android系统“我已完成activity的使用,现在不需要它了.”接到指令后,系统立即销毁了activity.即调用onPause()->onStop()-> ...

  8. android布局margin和padding差异!

    事实上从使用的时候就能够差别开来. android:padding android:layout_margin padding是在本控件级别的,而margin是在layout级别的. 最好拿有背景的控 ...

  9. 大豆生物柴油驱动的大巴斯(Bus)

    请看下图: 这是大豆生物柴油(Soybean biodiesel)驱动的大巴斯(Bus)的外观,感觉非常有劲. 回想历史,1893年,德国学者Rudolf Diesel(1858-1913)发明了一种 ...

  10. Mac 修改Host 绑定host

    Mac 系统下 ,修改Host 文件: 打开命令行终端 输入 sudo vi /etc/hosts 之后回车确认,进入vi 编辑界面(进行vi编辑操作,之后保存就行了) 版权声明:本文为博主原创文章, ...