- 浏览: 551646 次
- 来自: -
博客专栏
-
libgdx 游戏开发
浏览量:11985
文章分类
- 全部博客 (171)
- OS (1)
- JavaScript (13)
- Struts (2)
- Regular Expression (1)
- Java (14)
- HTML (4)
- XML (1)
- Non-Relational Database (2)
- Miscellaneous (7)
- Lotus Notes (8)
- Algorithm (3)
- Web Analytics (6)
- Web (8)
- Perl (3)
- PHP (3)
- C & C++ (1)
- Shell (7)
- Google (1)
- Android (31)
- iPhone (1)
- SQL (1)
- HTML5 (3)
- jQuery (6)
- CSS (6)
- PostgreSQL (1)
- Design Patterns (1)
- Excel (1)
- Magento (4)
- jMeter (3)
- SEO (1)
- libgdx (5)
- Software (4)
- App (1)
- Game (1)
- Gradle (1)
- Linux (16)
- Ubuntu (4)
- Docker (2)
- Spring (2)
- Other (3)
- Directory Server (1)
- CentOS (1)
- Python (1)
- VCS (3)
- Database (1)
- Open Source (1)
最新评论
-
ls0609:
赞一个,支持下博主。
[原创] Android ListView 在右上角添加三角形图标和文字 -
love297:
不让别人商用,自己先商用起来了。
手机游戏开发展示 -
a851206:
你的有些类是哪里来的?我想研究一下你的程序,可是有些类没有代码 ...
[原创] Google Custom Search & Yahoo Boss Search | Web Search API 使用 -
ypppk:
BitmapFactory.Options options = ...
[原创] 连载 1 - 深入讨论 Android 关于高效显示图片的问题 - 如何高效的加载大位图 -
笑遍世界:
我也遇到了,弄清了其中原因,可参考我的博客:http://sm ...
[原创] 使用 jMeter 登录 Wordpress
[原创] 连载 5 - 深入讨论 Android 关于高效显示图片的问题 - 如何在 UI 中显示位图
- 博客分类:
- Android
更加详细的说明,可以参阅如下官网地址:http://developer.android.com/training/building-graphics.html
快速导航
1. 如何高效的加载大位图。(如何解码大位图,避免超过每个应用允许使用的最大内存)http://yhz61010.iteye.com/blog/1848337
2. 如何在非 UI 线程处理位图。(如何使用 AsyncTask 在后台线程处理位图及处理并发问题)http://yhz61010.iteye.com/blog/1848811
3. 如何对位图进行缓存。(如何通过创建内存缓存和磁盘缓存来流畅的显示多张位图)http://yhz61010.iteye.com/blog/1849645
4. 如何管理位图内存。(如何针对不同的 Android 版本管理位图内存)http://yhz61010.iteye.com/blog/1850232
5. 如何在 UI 中显示位图。(如何通过 ViewPager 和 GridView 显示多张图片)http://yhz61010.iteye.com/blog/1852927
如何在 UI 中显示位图?
本文将引导你将前四篇的文章结合在一起,为你演示如何使用 ViewPager 和 GridView 组件在后台线程组合缓存加载多张位图,并且还将为你演示如何处理并发及配置改变的问题。
实现向 ViewPager 中添加位图
在浏览大量图片时,若允许用户滑动屏幕就可以切换图片的话,是非常好的导航模式 http://developer.android.com/design/patterns/swipe-views.html。你可以使用 ViewPager 组件的 PagerAdapter 来实现这种导航方式。但若使用它的子类 FragmentStatePagerAdapter 可能更加合适,因为当图片不再被显示的时候,该类会自动清理并保存 ViewPager 中的 Fragments 的状态,以节约内存的使用量。
注意,若你只想展示少量的图片,并且可以保证这些图片所占的内存不会超过应用程序的内存限制的话,那么你可以使用普通的 PagerAdapter 或 FragmentPagerAdapter 即可。
现在将为你展示如何使用 ViewPager 显示多个 ImageView。在主 activity 中声明了 ViewPager 和 adapter:
下面的代码为你详细的展现了持有 ImageView 的 Fragment 的实现。下面的代码看似是个完美的解决办法,但是你看出其中的不足了吗?应该如何改进呢?
你可能注意到问题的所在,图片是在 UI 线程中被加载的,这可能导致你的程序没有响应或被强制关闭。使用前文 http://yhz61010.iteye.com/blog/1848811 提到的 AsyncTask 来解决这个问题,将加载图片的处理放到后台线程来处理:
将任何耗时的处理(例如,获取来自网络中的图片或调整其大小)放到 BitmapWorkerTask 中,这样就不会给主 UI 线程带来任何响应的问题。后台线程的工作不仅仅是从磁盘中直接加载图片,而且还应该包括对图片进行缓存处理,这一点在 http://yhz61010.iteye.com/admin/blogs/1849645 一文中已经有了深入的讨论。下面,我们对代码做进一步的修改,以支持对内存缓存的处理:
将上述代码结合在一起,你就得到了一个响应及时的 ViewPager 实现。在该实现中,你可以以最小的延迟在后台对图片进行各种各样的处理。
实现向 GridView 中添加位图
Grid List http://developer.android.com/design/building-blocks/grid-lists.html 特别适用于显示图片集。通过 GridView 组件可以实现一次性在屏幕中显示多张图片,并且可以提前为用户准备好上下滑动屏幕时需要显示的图片。若要实现这种类型的操作,我们必须保证用户使用的流畅性,并且内存的使用量是可控的,而且还要保证并发操作的正确性(因为 GridView 会重用它的子视图)。
在开始了解具体的实现之前,我们先来看一个在 Fragment 中,使用带有 ImageView 的标准的 GridView 实现代码。然后再来分析下,这看似完美的实现方式背后还有没有更好的实现方式?
上述代码的问题和之前的例子一样,对图片的处理依然放在了 UI 线程。对于展示小的图片来说,这么做可能不会产生任何问题,但是如果我们还需要对显示的图片进行额外的处理话,上面的代码很可能会导致你的程序崩溃。
虽然这次我们依然可以使用刚才提到的异步处理及缓存处理,但是依然要谨慎的做好并发处理,因为 GridView 会重用它的子视图。为了处理这个问题,我们可以使用在 http://yhz61010.iteye.com/blog/1848811 一文中,“并发处理”章节中使用的技术。下面是对上述代码的改进版:
注意,将上述代码做适当修改还可以应用在 ListView 中。
上述代码实现中,让我们可以灵活的加载并处理图片,而且还不影响用户的使用体验。在后台的任务中,你可以从网络中加载图片,并调整高清图片的大小,在任务结束后再展现处理后的图片。
快速导航
1. 如何高效的加载大位图。(如何解码大位图,避免超过每个应用允许使用的最大内存)http://yhz61010.iteye.com/blog/1848337
2. 如何在非 UI 线程处理位图。(如何使用 AsyncTask 在后台线程处理位图及处理并发问题)http://yhz61010.iteye.com/blog/1848811
3. 如何对位图进行缓存。(如何通过创建内存缓存和磁盘缓存来流畅的显示多张位图)http://yhz61010.iteye.com/blog/1849645
4. 如何管理位图内存。(如何针对不同的 Android 版本管理位图内存)http://yhz61010.iteye.com/blog/1850232
5. 如何在 UI 中显示位图。(如何通过 ViewPager 和 GridView 显示多张图片)http://yhz61010.iteye.com/blog/1852927
如何在 UI 中显示位图?
本文将引导你将前四篇的文章结合在一起,为你演示如何使用 ViewPager 和 GridView 组件在后台线程组合缓存加载多张位图,并且还将为你演示如何处理并发及配置改变的问题。
实现向 ViewPager 中添加位图
在浏览大量图片时,若允许用户滑动屏幕就可以切换图片的话,是非常好的导航模式 http://developer.android.com/design/patterns/swipe-views.html。你可以使用 ViewPager 组件的 PagerAdapter 来实现这种导航方式。但若使用它的子类 FragmentStatePagerAdapter 可能更加合适,因为当图片不再被显示的时候,该类会自动清理并保存 ViewPager 中的 Fragments 的状态,以节约内存的使用量。
注意,若你只想展示少量的图片,并且可以保证这些图片所占的内存不会超过应用程序的内存限制的话,那么你可以使用普通的 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); } } }
下面的代码为你详细的展现了持有 ImageView 的 Fragment 的实现。下面的代码看似是个完美的解决办法,但是你看出其中的不足了吗?应该如何改进呢?
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 } }
你可能注意到问题的所在,图片是在 UI 线程中被加载的,这可能导致你的程序没有响应或被强制关闭。使用前文 http://yhz61010.iteye.com/blog/1848811 提到的 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); } } }
将任何耗时的处理(例如,获取来自网络中的图片或调整其大小)放到 BitmapWorkerTask 中,这样就不会给主 UI 线程带来任何响应的问题。后台线程的工作不仅仅是从磁盘中直接加载图片,而且还应该包括对图片进行缓存处理,这一点在 http://yhz61010.iteye.com/admin/blogs/1849645 一文中已经有了深入的讨论。下面,我们对代码做进一步的修改,以支持对内存缓存的处理:
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 }
将上述代码结合在一起,你就得到了一个响应及时的 ViewPager 实现。在该实现中,你可以以最小的延迟在后台对图片进行各种各样的处理。
实现向 GridView 中添加位图
Grid List http://developer.android.com/design/building-blocks/grid-lists.html 特别适用于显示图片集。通过 GridView 组件可以实现一次性在屏幕中显示多张图片,并且可以提前为用户准备好上下滑动屏幕时需要显示的图片。若要实现这种类型的操作,我们必须保证用户使用的流畅性,并且内存的使用量是可控的,而且还要保证并发操作的正确性(因为 GridView 会重用它的子视图)。
在开始了解具体的实现之前,我们先来看一个在 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; } } }
上述代码的问题和之前的例子一样,对图片的处理依然放在了 UI 线程。对于展示小的图片来说,这么做可能不会产生任何问题,但是如果我们还需要对显示的图片进行额外的处理话,上面的代码很可能会导致你的程序崩溃。
虽然这次我们依然可以使用刚才提到的异步处理及缓存处理,但是依然要谨慎的做好并发处理,因为 GridView 会重用它的子视图。为了处理这个问题,我们可以使用在 http://yhz61010.iteye.com/blog/1848811 一文中,“并发处理”章节中使用的技术。下面是对上述代码的改进版:
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
注意,将上述代码做适当修改还可以应用在 ListView 中。
上述代码实现中,让我们可以灵活的加载并处理图片,而且还不影响用户的使用体验。在后台的任务中,你可以从网络中加载图片,并调整高清图片的大小,在任务结束后再展现处理后的图片。
发表评论
-
[转] DialogFragment Fragment already added
2017-10-25 11:16 2626原文地址:http://blog.csdn.net/u0129 ... -
Android Studio .gitignore
2017-10-16 15:44 847参考文献: https://github.com/github ... -
[转] How to detect incoming calls in an Android
2017-10-13 14:14 1175原文地址:https://stackoverflow.com/ ... -
[转] Android 检测电源按钮是否被按下
2017-10-11 12:55 974原文地址:https://stackoverflow.com/ ... -
[原创] Android Activity onNewIntent() 详解
2017-08-16 13:46 4729阅读难度:中 阅读前提: 1. 需要了解 Android 的生 ... -
[转] Android Webview: “Uncaught TypeError: Cannot read property 'getItem' of null
2017-08-14 15:09 2253原文地址:https://stackoverflow.com/ ... -
[原创] 使用 Vitamio 播放视频作为 Splash 时出现失真情况的解决方案
2017-08-02 09:10 1190目前在做关于视频及流媒体播放项目时,有这样一个需求,应用启动时 ... -
[转] Android: Expand/collapse animation
2017-07-31 14:57 1543原文地址:https://stackoverflow.com/ ... -
[原创] Android ListView 在右上角添加三角形图标和文字
2017-07-26 17:24 2695最终显示效果如下图,在右上角添加三角形图标并在图标内显示文字: ... -
[转] Detect home button press in android
2017-07-20 17:49 1152原文地址:https://stackoverflow.com/ ... -
[原创] 开启 Android TextView Marquee
2017-07-18 15:47 1787亲测可能。直接上代码。 测试机器:XiaoMi 2S Andr ... -
[原创] 小米手机无法真机调试
2017-07-06 09:10 6455系统环境: 小米 2S MIUI 版本:8.0.1.0(LXA ... -
了解数据绑定 - Data Binding Library
2017-06-22 15:31 906原文地址: -
How to play gif with Fresco
2017-06-22 14:00 636原文地址:https://stackoverflow.com/ ... -
设置 Toolbar(ActionBar) 上的按钮颜色
2017-06-22 08:11 2043原文地址: https://stackoverflow.com ... -
Display back button on action bar and back event
2017-06-22 08:00 719原文地址: https://stackoverflow.com ... -
Gradle 修改 Maven 仓库地址
2017-06-02 15:51 1635修改 Gradle Maven 仓库地址为阿里云镜像 修改根 ... -
[转] How to clear cookies and cache of webview on Android when not in webview?
2017-04-26 09:28 2171原文地址:http://stackoverflow.com/a ... -
[转] Android 在程序中如何动态的修改程序图标
2017-03-02 17:05 887http://stackoverflow.com/a/4150 ... -
[转] Android Libraries
2017-01-16 10:28 543原文地址: https://dzone.com/article ...
相关推荐
Android-awesome-android-ui.zip,一份精选的android ui/ux库列表,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性优势。
1.2项目概述本文档适用于“中兴Android系统界面软件设计与开发”项目(以下简称“AndroidUI项目”)的开发过程 1.3文档概述本文档依据国家标准《G
•Android---UI篇---Tab Layout(选项卡布局) • •Andorid---UI篇---TableLayout(表格布局) • •Android---UI篇---RelativeLayout(相对布局) • •Android---UI篇---GridView(网格布局) • •Android---UI篇-...
用于为Office和Office 365构建体验的Android UI框架。
android UI界面开发图片,数量巨大,而且经典,觉得值得收藏 android UI界面开发图片,数量巨大,而且经典,觉得值得收藏
1.2 项目概述本文档适用于“中兴Android系统界面软件设计与开发”项目(以下简称“AndroidUI项目”)的开发过程 1.3 文档概述本文档依据国家标准
1.2项目概述本文档适用于“中兴Android系统界面软件设计与开发”项目(以下简称“AndroidUI项目”)的开发过程 1.3文档概述本文档依据国家标准《G
Android-cardslider-android.zip,CardSlider是一个材质设计的用户界面控制器,允许您在带有图片和附带说明的卡片中进行刷卡操作。-https://github.com/ramotion/android-ui-animation-components-and-libraries网站,...
Android-android-ui-animation-components-and-libraries.zip,android ui库、组件和动画作者@ramotion-https://github.com/ramotion/swift-ui-animation-components-libraries,安卓系统是谷歌在2008年设计和制造的。...
聊天UIDemo,支持文字、表情、语音、图片的聊天UI界面
Element-UI升级后,el-table不显示 空白问题 备份包
Android UI设计内容简介: 创造一个统一外观,感觉完整的用户界面会增加你的产品附加价值。 精炼的图形风格也使用户觉得用户界面更加专业。 帮助你如何在应用界面的不同部分创造图标来匹配 Android 2.x框架下的普遍...
GifView 是一个为了解决android中现在没有直接显示gif的view,只能通过mediaplay来显示这个问题的项目,其用法和 ImageView一样,支持gif图片 使用方法:1-把GifView.jar加入你的项目。2-在xml中配置GifView的基本...
mobyfactory-uiwidgets-android mobyfactory-uiwidgets-android
教程名称: 老罗Android开发视频教程-Android常用UI控件编程【32集】【】Android常用UI控件编程第七集【】Android常用UI控件编程第二十三集【】Android常用UI控件编程第二十九集【】Android常用UI控件编程第二十二...
1、查看网络上的图片 2、主线程阻塞-ANR 3、刷新UI-Handler 4、在本地缓存图片-例如微信的图片 5、获取开源代码 6、显示一个新闻客户端 7、使用GET方式提交表单数据 8、使用POST方式提交表单
Android-UI-Design 关于Android UI方面的讲解,希望对新手有一定的帮助
LoginUI-Android:在Android中的用户登录界面,具有创新,美观和创意背景
Dashboard-UI-Android:Android Studio中的简单Dashboard UI
Remixer是通过允许您调整UI变量而不需要重新构建(甚至重新启动)您的应用程序来快速迭代UI更改的框架。 您可以调整数字,颜色,布尔和字符串。