- 浏览: 561438 次
- 来自: -
博客专栏
-
libgdx 游戏开发
浏览量:12245
文章分类
- 全部博客 (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 2749原文地址:http://blog.csdn.net/u0129 ... -
Android Studio .gitignore
2017-10-16 15:44 908参考文献: https://github.com/github ... -
[转] How to detect incoming calls in an Android
2017-10-13 14:14 1233原文地址:https://stackoverflow.com/ ... -
[转] Android 检测电源按钮是否被按下
2017-10-11 12:55 1060原文地址:https://stackoverflow.com/ ... -
[原创] Android Activity onNewIntent() 详解
2017-08-16 13:46 4807阅读难度:中 阅读前提: 1. 需要了解 Android 的生 ... -
[转] Android Webview: “Uncaught TypeError: Cannot read property 'getItem' of null
2017-08-14 15:09 2360原文地址:https://stackoverflow.com/ ... -
[原创] 使用 Vitamio 播放视频作为 Splash 时出现失真情况的解决方案
2017-08-02 09:10 1228目前在做关于视频及流媒体播放项目时,有这样一个需求,应用启动时 ... -
[转] Android: Expand/collapse animation
2017-07-31 14:57 1590原文地址:https://stackoverflow.com/ ... -
[原创] Android ListView 在右上角添加三角形图标和文字
2017-07-26 17:24 2790最终显示效果如下图,在右上角添加三角形图标并在图标内显示文字: ... -
[转] Detect home button press in android
2017-07-20 17:49 1189原文地址:https://stackoverflow.com/ ... -
[原创] 开启 Android TextView Marquee
2017-07-18 15:47 1829亲测可能。直接上代码。 测试机器:XiaoMi 2S Andr ... -
[原创] 小米手机无法真机调试
2017-07-06 09:10 6508系统环境: 小米 2S MIUI 版本:8.0.1.0(LXA ... -
了解数据绑定 - Data Binding Library
2017-06-22 15:31 984原文地址: -
How to play gif with Fresco
2017-06-22 14:00 674原文地址:https://stackoverflow.com/ ... -
设置 Toolbar(ActionBar) 上的按钮颜色
2017-06-22 08:11 2092原文地址: https://stackoverflow.com ... -
Display back button on action bar and back event
2017-06-22 08:00 768原文地址: https://stackoverflow.com ... -
Gradle 修改 Maven 仓库地址
2017-06-02 15:51 1696修改 Gradle Maven 仓库地址为阿里云镜像 修改根 ... -
[转] How to clear cookies and cache of webview on Android when not in webview?
2017-04-26 09:28 2211原文地址:http://stackoverflow.com/a ... -
[转] Android 在程序中如何动态的修改程序图标
2017-03-02 17:05 956http://stackoverflow.com/a/4150 ... -
[转] Android Libraries
2017-01-16 10:28 576原文地址: https://dzone.com/article ...
相关推荐
在Android开发中,GridView是一种常见...综上所述,解决GridView加载大量图片卡顿的问题需要结合异步加载技术、高效的缓存策略以及合理的图片处理,通过这些方法,我们能够显著提升用户体验,打造流畅的图片加载效果。
总之,将Android的彩色位图转换为单色位图涉及到位图的加载、配置创建、像素转换以及保存或显示。这个过程需要对Android图形系统有深入的理解,并可能需要用到原生代码来实现1位深度的支持。通过这样的转换,开发者...
在Android开发中,将网络上的图片加载到ImageView控件上是一项常见的需求,特别是在构建社交应用、电商应用或者新闻阅读类应用时。这个过程涉及到多个关键知识点,包括网络请求、图片缓存策略、线程管理以及UI更新等...
在MFC(Microsoft Foundation Classes)框架中,加载位图并实现图片的放大和缩小功能是一项常见的任务,尤其在开发图形用户界面(GUI)应用程序时。本文将深入探讨如何使用MFC来实现这一功能。 首先,我们需要了解...
Glide是一个流行的Android图片加载库,它以其高效、易用和强大的功能而闻名。本篇将详细讲解如何在Android应用中使用Glide加载SVG图像。 首先,我们需要了解SVG的基本概念。SVG是一种基于XML的图形语言,它可以描绘...
本笔记将深入探讨如何高效地加载和管理高清大图,避免内存溢出(Out Of Memory,OOM)问题。 一、Bitmap对象与内存管理 1. Bitmap对象在内存中的存储:Android将Bitmap数据存储为一个像素数组,占用连续的内存空间...
在Android开发中,大位图(Bitmap)的处理是一个重要的技术点,特别是在处理高分辨率图像或者需要显示大量图片的应用中。由于Android系统对内存管理的限制,直接加载大位图可能导致应用崩溃,这就是著名的"Out of ...
在VC++编程中,有时我们需要将位图显示在窗口上,并且希望窗口能根据位图的大小自动调整,以确保位图能完全显示。这个任务可以通过处理窗口消息和使用GDI(Graphics Device Interface)来实现。下面我们将深入探讨...
在Android开发中,Glide是一个非常流行的图片加载库,它以其高效、易用和强大的功能深受开发者喜爱。SVG(Scalable Vector Graphics)是一种矢量图格式,与传统的位图图像不同,SVG图像可以无损缩放,不会因为放大而...
本文将深入探讨如何处理图片的压缩、显示以及解决颜色失真的问题。 首先,我们关注“窗口显示图片”这个主题。在各种操作系统中,无论是Windows、macOS还是Linux,窗口系统都提供了API或库函数来支持图像的加载和...
在C++编程中,加载位图并将其显示在窗口上是一项基本任务,尤其在游戏开发中至关重要。位图(Bitmap)是一种常见的图像文件格式,它包含像素数据,用于表示图像。下面将详细介绍如何使用C++来实现这个过程,并提供...
位图是一种图像文件格式,通常用于显示静态图片。本篇文章将详细讲解如何在基于MFC对话框的应用程序中加载位图。 1. **位图资源的准备** 在开始编码之前,你需要有一个位图文件(如.bmp)。确保这个文件已经包含在...
在Android应用中,直接在主线程加载大图或网络图片可能导致应用无响应(ANR),因此异步加载成为必备功能。该控件支持在后台线程加载图片,避免阻塞UI,提高应用的响应速度。同时,它可能采用了诸如Picasso、Glide...
本示例“android中的位图操作demo”主要涵盖了Android应用开发中关于位图的基本操作,包括位图的加载、绘制以及一些高级功能,如创建倒影效果。以下是对这些知识点的详细说明: 1. **位图的加载**:在Android中,...
在Android开发中,ImageView是用于显示图像资源的重要组件。它能够加载本地图片或者网络图片,是用户界面设计中不可或缺的一部分。本篇文章将深入探讨ImageView的工作原理、如何使用以及相关的优化技巧。 1. **...
总结,"android-image-filter-ndk"项目为我们提供了一个实战范例,展示了如何结合Android NDK和C语言实现高效的图像处理。通过学习该项目,开发者不仅可以掌握Android NDK的使用,还能深入理解图像处理的原理和技巧...
1. 内存限制:Android系统对每个应用分配了一定量的内存,当加载大位图时,如果超过分配的内存限制,可能会引发OutOfMemoryError。 2. 图片解码:大位图在内存中解码时会占用大量空间,即使图片在磁盘上的大小并不大...
本资源"Android应用源码之Android 图片缓存、加载器.zip"提供了一个实际的安卓实例,旨在帮助开发者理解和实现高效的图片处理机制。以下将详细阐述相关知识点。 1. **图片加载库的选择与原理** - Android开发中...
1. **图片加载库**:在Android中,高效地加载和显示图片是必不可少的。源码可能使用了如Glide、Picasso或 Fresco等流行的图片加载库,它们能优化内存使用,避免内存溢出,并提供缓存机制。 2. **手势识别**:为了...
在实际开发中,我们可能会遇到性能问题,特别是处理大尺寸图片时。为了避免内存溢出,可以考虑使用Bitmap的inSampleSize来降低图片加载的分辨率,或者使用BitmapRegionDecoder来按需解码部分图像。 JImageEditDemo...