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

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

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. BZOJ 1531: [POI2005]Bank notes( 背包 )

    多重背包... ---------------------------------------------------------------------------- #include<bit ...

  2. 终于懂了:Delphi重定义消息结构随心所欲,只需要前4个字节是消息编号就行了(有了这个,就有了主动)

    Delphi重定义消息结构随心所欲,只需要前4个字节是消息编号就行了,跟Windows消息虽然尽量保持一致,但其实相互没有特别大的关系.有了这个,就有了主动,带不带句柄完全看需要. 比如这个结构就带句 ...

  3. 获取wpf datagrid当前被编辑单元格的内容

    原文 获取wpf datagrid当前被编辑单元格的内容 确认修改单元个的值, 使用到datagrid的两个事件 开始编辑事件 BeginningEdit="dataGrid_Beginni ...

  4. boost 轻量级信号量

    #include <boost/thread/condition_variable.hpp> #include <boost/thread/mutex.hpp>     #in ...

  5. Objective-C中的SEL、IMP和Class类型

    1.SEL类型 例子: SEL say;        SEL skin; Objective-C 在编译的时候, 会根据方法的名字(包括参数序列),生成一个用 来区分这个方法的唯一的一个 ID,这个 ...

  6. 【剑指offer】树的子结构

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/25907685 剑指offer第18题,九度OJ上測试通过! 题目描写叙述: 输入两颗二叉树 ...

  7. delphi 利用HTTP的POST方法做个在线翻译的小工具 good

    最近做了一个英汉小翻译的东东,用的是VC,ADO + Access访问数据库,单词数据库是从金山打字通2002弄来的.后来想了想,想再加个在线翻译的功能,记得经常使用GOOGLE翻译网站的在线翻译,也 ...

  8. Redis核心解读:集群管理工具(Redis-sentinel)

    Redis核心解读:集群管理工具(Redis-sentinel) - Redis - TechTarget数据库 Redis核心解读:集群管理工具(Redis-sentinel)

  9. Swift代码实现加载WEBVIEW

    let webview = UIWebView(frame:self.view.bounds) webview.bounds=self.view.bounds //远程网页 webview.loadR ...

  10. MFC的消息机制

    MFC的消息循环(::GetMessage,::PeekMessage)消息泵(CWinThread::PumpMessage)和MFC的消息在窗口之间的路由是两件不同的事情 分两个步骤完成: 1 “ ...