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

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

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. ubuntu 安装LaTex

    使用IDE来使用tex,如TexMaker. 1.到http://www.tug.org/texlive/acquire-netinstall.html 下载texlive. 2.linux下命令行, ...

  2. c语言, objective code(new 2)

    参考: 1. C中的继承和多态 http://www.cnblogs.com/skynet/archive/2010/09/23/1833217.html

  3. SQLiteLog (1) no such Column:

           今天在进入sqlite数据库查询的时候出现了这个问题,SQLiteLog (1) no such Column: BGZ 搜索得知这是因为数据库中没有这一列,我的sql语句为" ...

  4. ASP.NET - 一般处理程序获取session值

    1.要在一般处理程序中获取其他页面的session值,需要引用名空间: using System.Web.SessionState; 2.然后继承一个接口:IRequiresSessionState, ...

  5. ALV前导零的问题

    ALV的IT_FIELDCAT参数中L_ZERO 选项置位的话,对NUM类型的前导0是可以输出的,但是有个很重要的前提条件,NO_ZERO不可以置位,否则L_ZERO是失效的.

  6. 51cto大数据培训路线

    Java Java IO/NIO JVM原理与配置.调优 Socket 网络套接字技术 Java Collection java Reflection 多线程与并发编程 设计模式 Collection ...

  7. XP教育网用户免费上网

      本文针对 XP 教育网用户免费上网,其他系统未作测试.若有疑问百度空间留言 http://hi.baidu.com/itas109 http://blog.csdn.net/itas109 步骤 ...

  8. hdu 4712 Hamming Distance bfs

    我的做法,多次宽搜,因为后面的搜索扩展的节点会比较少,所以复杂度还是不需要太悲观的,然后加上一开始对答案的估计,用估计值来剪枝,就可以ac了. #include <iostream> #i ...

  9. sofa-pbrpc 1.1.1 发布,RPC 网络通信库

    https://www.oschina.net/news/77372/sofa-pbrpc-1-1-1 https://www.oschina.net/p/sofa-pbrpc

  10. POJ 1862 &amp; ZOJ 1543 Stripies(贪心 | 优先队列)

    题目链接: PKU:http://poj.org/problem?id=1862 ZJU:http://acm.zju.edu.cn/onlinejudge/showProblem.do?proble ...