由于本人英文能力实在有限,不足之初敬请谅解
本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接
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?
下面是详细的Fragment持有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地址
相关推荐
1. **Android基础知识**:在Android开发中,理解基本概念如Activity、Intent、Service、Broadcast Receiver和Content Provider至关重要。这些构成了Android应用的核心架构,学习它们的工作原理能帮助开发者构建功能...
这个压缩包中的核心文件是"Android中文翻译组——Android中文API合集(4).chm",它包含了大量与Android开发相关的API详细说明,使得开发者在进行程序设计时能够快速理解和应用。 Android API是Android操作系统的...
在Android开发领域,掌握官方API文档是至关重要的,因为它提供了详细的API接口、类库以及方法说明,帮助开发者深入理解Android系统的运作机制和编程模型。虽然大部分Android开发者习惯于查阅英文版的官方文档,但...
这篇文档是Android开发中关于`android.widget`包的一个中文翻译合集,主要针对Android平台上常用的Widget组件进行深入解析。`android.widget`是Android SDK中的核心包之一,包含了大量用于构建用户界面(UI)的基本...
《Android中文合集》是一个全面且丰富的资源包,包含了126篇文章以及额外的8篇精选内容,专门针对Android开发进行深入讲解。这个资源库旨在为Android开发者提供一个全面的学习平台,涵盖了从基础到进阶的各种知识点...
Android API是Google为Android操作系统提供的开发接口,它包含了众多的类库、方法和工具,用于构建运行在Android设备上的应用程序。Android API的详细学习是每个Android开发者入门和进阶的必经之路。中文API的翻译...
这个"android中文API"是一个非完整的汉化版本,意味着它只包含了部分已经翻译成中文的API文档,主要目标是为了帮助那些在阅读英文API时遇到困难的开发者。对于那些不熟悉或者不擅长英语的开发者来说,这是一个极其有...
在Android平台上进行文本检测是一项重要的任务,特别是在移动应用开发中,如 OCR(光学字符识别)、文档扫描、实时翻译等场景。本项目“Android-Text-Detection”专注于利用Java语言实现这一功能。以下将详细介绍...
随着智能手机的普及,用户需要快速、准确地从图片中提取文字,这在日常生活中有着广泛的应用,如扫描文档、翻译、记录笔记等。本项目“android-recognition”就是针对这一需求而开发的一款基于Java的Android应用,它...
在项目中,Java可能会使用OpenCV或Android的Bitmap类进行这些操作。 五、OCR引擎集成 Tesseract OCR的集成涉及添加依赖项到项目的build.gradle文件,然后在代码中创建TessBaseAPI对象,设置识别的语言,并调用它的...
OCR技术在移动设备上的应用广泛,包括扫描文档、翻译、发票识别、名片管理等。开发者可以根据需求定制特定的OCR解决方案,提升用户的生活和工作效率。 综上所述,这个三年前的Android OCR图像识别程序展现了开发者...