- 浏览: 552454 次
- 来自: -
博客专栏
-
libgdx 游戏开发
浏览量:12006
文章分类
- 全部博客 (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
[原创] 连载 1 - 深入讨论 Android 关于高效显示图片的问题 - 如何高效的加载大位图
- 博客分类:
- Android
更加详细的说明,可以参阅如下官网地址:http://developer.android.com/training/building-graphics.html
刚开始做 Android 应用时,以为显示图片是很简单的事,在模拟器里运行的好好的,一放到真机上,经常遇到类似于 java.lang.OutofMemoryError: bitmap size exceeds VM budget. 之类的异常。后来看了下官网的详细的介绍,才发现关于图片的显示说头还不少。
下面就把学习心得与大家分享下:
为什么显示图片会遇到很棘手的问题?
手机显示一张 800 万像素的图片(现在主流的手机像素基本上都是 800 万像素以上),大约需要使用 32 MB 的内存,而这刚好是 Android 系统分配给每个应用的最大内存(有的 Android 设备分配给每个应用的最大内存只有 16 MB),所以如果手机应用直接打开这样一张图,基本上都会遇到由于内存溢出而导致程序被迫退出的情况。相信这种情况很多人可能都遇到过。
以 Galaxy Nexus 为例,其后置相机的像素是 500 万,其分辨率为 2592x1936 像素。若位图设置使用的是 ARGB_8888 (在 Android 2.3 及更高版本中,该值为默认值),那么加载该图将占用大约 19 MB 的内存(2592*1936*4 bytes),因此程序很快就会耗尽 Android 分配给每个应用程序的最大内存,从而导致程序崩溃。
即使应用程序不见得非要显示一张 500 万或更高像素的图片,如果程序设计不当,同样会在显示图片时,遇到程序崩溃的问题。例如,在图片相关的应用中,经常需要显示大量图片,因此经合会使用 ListView, GridView 或 ViewPager。若不对显示的图片进行处理,也会由于显示图片过多而导致程序崩溃。
如何解决显示图片导致的内存溢出的问题?
要解决这个问题,需要从以下五点入手:
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
下面我们来一一进行说明。
如何高效的加载大位图?
1. 获取位置尺寸及类型
使用 BitmapFactory 对位图进行解码时,使用 BitmapFactory.Options。将 Options 的 inJustDecodeBounds 设置为 true 时,可以避免为位图分配内存,此时 BitmapFactory.decodeX 的返回结果为 null,但是会为 Options 设置 outWidth, outHeight 和 outMimeType 值。
通过上述代码,你就可以在不为位图分配内存的情况下,获得位图的宽,高及位图类型。之后在显示图片时,就可以通过获取的信息来判断是否需要对图片进行处理后再显示,从而避免内存溢出问题。
2. 将缩小比例后的图片加载到内存
若程序中仅仅是为了显示一张 128x96 大小的缩略图,而将一张原始大小为 1024x768 的图片加载到内存,就显得很不划算了。因此,对将要显示的图片进行等比例缩小后再进行显示就显得很有必要。
通过设置 options.inSampleSize 来产生缩小后的图片。例如,若 options.inSampleSize = 4,那么对于一张原始大小为 2048x1536 的位图来说,产生的新位图大小约为 512x384。将这个新的位图加载到内存只需要 0.75 MB 内存,而原图则需要占用大约 12 MB 的内存。
具体程序实现如下:
首先,将 inJustDecodeBounds 设置为 true,获取位图信息,然后再设置新的 inSampleSize 值,最后再将 inJustDecodeBounds 设置为 false,从而将新生成的位图加载至内存。
上述方法中使用的 calculateInSampleSize 方法的实现如下:
需要注意的是,上述方法返回的 inSampleSize 的值,最好是 2 的 n 次幂。(详见 http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize)
综上所述,有了上述这些方法,我们就可以在程序中加载任意大小的图片,而不用担心内存溢出的问题。例如,下述代码会将原始图片显示成 100x100 像素的缩略图:
刚开始做 Android 应用时,以为显示图片是很简单的事,在模拟器里运行的好好的,一放到真机上,经常遇到类似于 java.lang.OutofMemoryError: bitmap size exceeds VM budget. 之类的异常。后来看了下官网的详细的介绍,才发现关于图片的显示说头还不少。
下面就把学习心得与大家分享下:
为什么显示图片会遇到很棘手的问题?
手机显示一张 800 万像素的图片(现在主流的手机像素基本上都是 800 万像素以上),大约需要使用 32 MB 的内存,而这刚好是 Android 系统分配给每个应用的最大内存(有的 Android 设备分配给每个应用的最大内存只有 16 MB),所以如果手机应用直接打开这样一张图,基本上都会遇到由于内存溢出而导致程序被迫退出的情况。相信这种情况很多人可能都遇到过。
以 Galaxy Nexus 为例,其后置相机的像素是 500 万,其分辨率为 2592x1936 像素。若位图设置使用的是 ARGB_8888 (在 Android 2.3 及更高版本中,该值为默认值),那么加载该图将占用大约 19 MB 的内存(2592*1936*4 bytes),因此程序很快就会耗尽 Android 分配给每个应用程序的最大内存,从而导致程序崩溃。
即使应用程序不见得非要显示一张 500 万或更高像素的图片,如果程序设计不当,同样会在显示图片时,遇到程序崩溃的问题。例如,在图片相关的应用中,经常需要显示大量图片,因此经合会使用 ListView, GridView 或 ViewPager。若不对显示的图片进行处理,也会由于显示图片过多而导致程序崩溃。
如何解决显示图片导致的内存溢出的问题?
要解决这个问题,需要从以下五点入手:
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
下面我们来一一进行说明。
如何高效的加载大位图?
1. 获取位置尺寸及类型
使用 BitmapFactory 对位图进行解码时,使用 BitmapFactory.Options。将 Options 的 inJustDecodeBounds 设置为 true 时,可以避免为位图分配内存,此时 BitmapFactory.decodeX 的返回结果为 null,但是会为 Options 设置 outWidth, outHeight 和 outMimeType 值。
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
通过上述代码,你就可以在不为位图分配内存的情况下,获得位图的宽,高及位图类型。之后在显示图片时,就可以通过获取的信息来判断是否需要对图片进行处理后再显示,从而避免内存溢出问题。
2. 将缩小比例后的图片加载到内存
若程序中仅仅是为了显示一张 128x96 大小的缩略图,而将一张原始大小为 1024x768 的图片加载到内存,就显得很不划算了。因此,对将要显示的图片进行等比例缩小后再进行显示就显得很有必要。
通过设置 options.inSampleSize 来产生缩小后的图片。例如,若 options.inSampleSize = 4,那么对于一张原始大小为 2048x1536 的位图来说,产生的新位图大小约为 512x384。将这个新的位图加载到内存只需要 0.75 MB 内存,而原图则需要占用大约 12 MB 的内存。
具体程序实现如下:
首先,将 inJustDecodeBounds 设置为 true,获取位图信息,然后再设置新的 inSampleSize 值,最后再将 inJustDecodeBounds 设置为 false,从而将新生成的位图加载至内存。
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
上述方法中使用的 calculateInSampleSize 方法的实现如下:
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // Calculate ratios of height and width to requested height and width final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // Choose the smallest ratio as inSampleSize value, this will guarantee // a final image with both dimensions larger than or equal to the // requested height and width. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; }
需要注意的是,上述方法返回的 inSampleSize 的值,最好是 2 的 n 次幂。(详见 http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize)
综上所述,有了上述这些方法,我们就可以在程序中加载任意大小的图片,而不用担心内存溢出的问题。例如,下述代码会将原始图片显示成 100x100 像素的缩略图:
mImageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
评论
1 楼
ypppk
2013-07-02
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.picture, options); //这里的位图是空的,原因是options.inJustDecodeBounds为true,但是可以获得位图的长宽,所以此次内存不会溢出
int orgHeight = options.outHeight;
int orgWidth = options.outWidth;
options.inSampleSize = orgWidth/Static.screenWidth; //按照比例缩放到屏幕宽度
options.inJustDecodeBounds = false;
Static.picture = BitmapFactory.decodeResource(getResources(), R.drawable.picture, options); //绘制缩放后的位图
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.picture, options); //这里的位图是空的,原因是options.inJustDecodeBounds为true,但是可以获得位图的长宽,所以此次内存不会溢出
int orgHeight = options.outHeight;
int orgWidth = options.outWidth;
options.inSampleSize = orgWidth/Static.screenWidth; //按照比例缩放到屏幕宽度
options.inJustDecodeBounds = false;
Static.picture = BitmapFactory.decodeResource(getResources(), R.drawable.picture, options); //绘制缩放后的位图
发表评论
-
[转] DialogFragment Fragment already added
2017-10-25 11:16 2634原文地址:http://blog.csdn.net/u0129 ... -
Android Studio .gitignore
2017-10-16 15:44 851参考文献: https://github.com/github ... -
[转] How to detect incoming calls in an Android
2017-10-13 14:14 1178原文地址:https://stackoverflow.com/ ... -
[转] Android 检测电源按钮是否被按下
2017-10-11 12:55 981原文地址:https://stackoverflow.com/ ... -
[原创] Android Activity onNewIntent() 详解
2017-08-16 13:46 4734阅读难度:中 阅读前提: 1. 需要了解 Android 的生 ... -
[转] Android Webview: “Uncaught TypeError: Cannot read property 'getItem' of null
2017-08-14 15:09 2257原文地址:https://stackoverflow.com/ ... -
[原创] 使用 Vitamio 播放视频作为 Splash 时出现失真情况的解决方案
2017-08-02 09:10 1194目前在做关于视频及流媒体播放项目时,有这样一个需求,应用启动时 ... -
[转] Android: Expand/collapse animation
2017-07-31 14:57 1546原文地址:https://stackoverflow.com/ ... -
[原创] Android ListView 在右上角添加三角形图标和文字
2017-07-26 17:24 2698最终显示效果如下图,在右上角添加三角形图标并在图标内显示文字: ... -
[转] Detect home button press in android
2017-07-20 17:49 1159原文地址:https://stackoverflow.com/ ... -
[原创] 开启 Android TextView Marquee
2017-07-18 15:47 1791亲测可能。直接上代码。 测试机器:XiaoMi 2S Andr ... -
[原创] 小米手机无法真机调试
2017-07-06 09:10 6461系统环境: 小米 2S MIUI 版本:8.0.1.0(LXA ... -
了解数据绑定 - Data Binding Library
2017-06-22 15:31 910原文地址: -
How to play gif with Fresco
2017-06-22 14:00 640原文地址:https://stackoverflow.com/ ... -
设置 Toolbar(ActionBar) 上的按钮颜色
2017-06-22 08:11 2049原文地址: https://stackoverflow.com ... -
Display back button on action bar and back event
2017-06-22 08:00 724原文地址: https://stackoverflow.com ... -
Gradle 修改 Maven 仓库地址
2017-06-02 15:51 1639修改 Gradle Maven 仓库地址为阿里云镜像 修改根 ... -
[转] How to clear cookies and cache of webview on Android when not in webview?
2017-04-26 09:28 2176原文地址:http://stackoverflow.com/a ... -
[转] Android 在程序中如何动态的修改程序图标
2017-03-02 17:05 891http://stackoverflow.com/a/4150 ... -
[转] Android Libraries
2017-01-16 10:28 547原文地址: https://dzone.com/article ...
相关推荐
mfc加载位图,并可以放大、缩小图片
android 多位图转化为单色位图。32位深图转1位深图。24位深转1位
VC++源代码,根据位图实际大小,自动调整窗口大小,显示位图
----------------------------------- Android 编程基础 1 封面----------------------------------- Android 编程基础 2 开放手机联盟 --Open --Open --Open --Open Handset Handset Handset Handset Alliance ...
资源中是一个vs2008sp1 IDE中VC++ MFC 图片控件(Picture Control)显示资源位图(BMP)、文件位图(BMP)、其它格式文件图片(JPG\PNG\BMP)的实例,可供参考。
商业编程-源码-位图的Alpha淡入淡出显示示例代码.zip
VC通过路径加载位图源码例子VC通过路径加载位图源码例子
利用C++编写位图加载程序,利用.BMP文件的格式加载文件并显示到窗口中
vc6 动态位图的加载
MFC 加载图片 动态加载图片 静态加载图片 ,解决了从网上找的代码的内存泄漏的问题。
一个简单的加载位图的例子,是基于MFC的,蛮简单的,需要的可以看看
QT加载几百M几G的超大bmp位图,用二进制方式解读bmp格式,通过cv::Mat转QImage获得,还有系统并发处理加速。
vc中如何显示位图vc中如何显示位图vc中如何显示位图vc中如何显示位图vc中如何显示位图
计算机软件-编程源码-8.11 特大位图的分块显示.zip
计算机软件-商业源码-实现位图显示特技.zip
实现VC中加载透明位图功能,实现的比较好还是。可以实现位图透明功能。
可以显示特大位图,解决位图太大而不能显示的问题.
能够在对话框的图片控件上显示位图 ,打开 ,连续显示,搜寻显示 ,单帧显示等
恒率电源 WRD110S51-40W隔离式高效开关电源模块资料脚位图pdf,恒率电源 WRD110S51-40W隔离式高效开关电源模块资料脚位图
1.如何通过读取位图资源显示位图?(Visual C++编程 源代码)1.如何通过读取位图资源显示位图?(Visual C++编程 源代码)1.如何通过读取位图资源显示位图?(Visual C++编程 源代码)1.如何通过读取位图资源显示...