- 浏览: 549319 次
- 来自: -
博客专栏
-
libgdx 游戏开发
浏览量:11916
文章分类
- 全部博客 (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
[原创] 连载 4 - 深入讨论 Android 关于高效显示图片的问题 - 如何管理位图内存
- 博客分类:
- 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
如何管理位图内存?
在http://yhz61010.iteye.com/blog/1849645一文中,我们已经讨论了如何对位图进行缓存处理。但还有一些具体的事情需要做,比如说如何更好的利用垃圾回收器和重用位图等。对于不同的 Android 版本,我们通常有不同的策略。
在我们开始今天的学习之前,先来了解下 Android 是如何管理位图内存的:
・在 Android 2.2 (API level及之前版本,当进行垃圾回收时,会停止你的应用程序线程,这样就会产生一个延迟,从而会影响性能。在 Android 2.3 中添加了并发的垃圾回收器,这就意味着若位图没有被任何对象引用的话,它所占用的内存就会很快被回收。
・在 Android 2.3.3 (API level 10) 及之前版本,返回的位图数据是保存在程序内存中的,和位图本身所占的内存是区分开的,位图本身是保存在 Dalvik 堆中的。返回的位图数据虽然保存在内存中,但是所占用的内存并不会按照可预知的方式将其释放掉,从而导致的潜在问题就是应用程序很容易就超过内存限制并导致程序崩溃。从 Android 3.0 (API Level 11) 开始,返回的位图数据及位图本身都被保存在 Dalvik 堆中。
下面我们就开始学习如何针对不同的 Android 版本进行位图内存优化。
Android 2.3.3 及早先版本的内存管理
在 Android 2.3.3 (API level 10)及早先版本中,建议使用 recycle() 进行内存管理。如果在你的程序中显示大量的位图数据,你很可能就会遇到 OutOfMemoryError 错误。recycle() 方法允许应用程序尽可能的回收内存。
注意:只有当你确信位图不再被使用时,才能调用 recycle() 方法。若你已经调用了 recycle() 方法,但是之后你却再次访问了那些位图,那么你会看到如下错误提示:"Canvas: trying to use a recycled bitmap"。
如下的代码片断为你演示了如何调用 recycle()。代码中使用了引用计数(保存在 mDisplayRefCount 和 mCacheRefCount 中)用来跟踪位图是正在被显示还是被保存在内存中。当满足如下条件时,位图将会被回收:
・引用计数变量 mDisplayRefCount 和 mCacheRefCount 的值都为 0。
・bitmap 对象不为 null,并且它还没被回收。
Android 3.0 及更高版本的内存管理
Android 3.0 (API Level 11) 引进了 BitmapFactory.Options.inBitmap 字段,如果设置了该属性,那么当使用了带有该 Options 参数的 decode 方法在加载内容时,decode 方法会尝试重用一个已经存在的位图。这就意味着位图内存已经被重用了,从而性能得到了改善,并且移除了内存的分配和解除分配。下面是一些使用 inBitmap 的注意事项:
・重用的位图大小必须和源位图大小相同(这样才能保证它们占用相同的内存),并且位图的格式应该是 JPEG 或 PNG(无论是作为资源形式还是数据流形式)。
・若设置了重用的位图的 Bitmap.Config 配置,则需要重写 inPreferredConfig 方法。
・你应该总是使用位图的解码方法,因为我们不能认为重用的位图是可用的(例如,若位图大小不匹配,就无法保证位图可重用)。
保存位图便于以后使用
如下的代码片断为你演示了位图是如何被保存便于以后使用的。当程序运行在 Android 3.0 或更高版本中时,位图将会从 LruCache 中被移除,指向该位图的 soft reference 将被存放在一个 HashSet 中,以便于之后在 inBitmap 中使用:
使用一个已经存在的位图
我们可以在程序中使用解码方法来判断是否有可重用的位图。例如:
上述代码中的 addInBitmapOptions() 方法实现如下。该方法会查找一个已经存在的位图,将并该位图设置给 inBitmap 属性。注意,只有当找到了一个匹配的位图时(我们永远不能假定这种匹配一定能被找到),该方法才会为 inBitmap 赋值。
最后,为了能给 inBitmap 赋值,我们还需要使用如下方法来判断是否有一个可选的位图满足指定的位图大小:
快速导航
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
如何管理位图内存?
在http://yhz61010.iteye.com/blog/1849645一文中,我们已经讨论了如何对位图进行缓存处理。但还有一些具体的事情需要做,比如说如何更好的利用垃圾回收器和重用位图等。对于不同的 Android 版本,我们通常有不同的策略。
在我们开始今天的学习之前,先来了解下 Android 是如何管理位图内存的:
・在 Android 2.2 (API level及之前版本,当进行垃圾回收时,会停止你的应用程序线程,这样就会产生一个延迟,从而会影响性能。在 Android 2.3 中添加了并发的垃圾回收器,这就意味着若位图没有被任何对象引用的话,它所占用的内存就会很快被回收。
・在 Android 2.3.3 (API level 10) 及之前版本,返回的位图数据是保存在程序内存中的,和位图本身所占的内存是区分开的,位图本身是保存在 Dalvik 堆中的。返回的位图数据虽然保存在内存中,但是所占用的内存并不会按照可预知的方式将其释放掉,从而导致的潜在问题就是应用程序很容易就超过内存限制并导致程序崩溃。从 Android 3.0 (API Level 11) 开始,返回的位图数据及位图本身都被保存在 Dalvik 堆中。
下面我们就开始学习如何针对不同的 Android 版本进行位图内存优化。
Android 2.3.3 及早先版本的内存管理
在 Android 2.3.3 (API level 10)及早先版本中,建议使用 recycle() 进行内存管理。如果在你的程序中显示大量的位图数据,你很可能就会遇到 OutOfMemoryError 错误。recycle() 方法允许应用程序尽可能的回收内存。
注意:只有当你确信位图不再被使用时,才能调用 recycle() 方法。若你已经调用了 recycle() 方法,但是之后你却再次访问了那些位图,那么你会看到如下错误提示:"Canvas: trying to use a recycled bitmap"。
如下的代码片断为你演示了如何调用 recycle()。代码中使用了引用计数(保存在 mDisplayRefCount 和 mCacheRefCount 中)用来跟踪位图是正在被显示还是被保存在内存中。当满足如下条件时,位图将会被回收:
・引用计数变量 mDisplayRefCount 和 mCacheRefCount 的值都为 0。
・bitmap 对象不为 null,并且它还没被回收。
private int mCacheRefCount = 0; private int mDisplayRefCount = 0; ... // Notify the drawable that the displayed state has changed. // Keep a count to determine when the drawable is no longer displayed. public void setIsDisplayed(boolean isDisplayed) { synchronized (this) { if (isDisplayed) { mDisplayRefCount++; mHasBeenDisplayed = true; } else { mDisplayRefCount--; } } // Check to see if recycle() can be called. checkState(); } // Notify the drawable that the cache state has changed. // Keep a count to determine when the drawable is no longer being cached. public void setIsCached(boolean isCached) { synchronized (this) { if (isCached) { mCacheRefCount++; } else { mCacheRefCount--; } } // Check to see if recycle() can be called. checkState(); } private synchronized void checkState() { // If the drawable cache and display ref counts = 0, and this drawable // has been displayed, then recycle. if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed && hasValidBitmap()) { getBitmap().recycle(); } } private synchronized boolean hasValidBitmap() { Bitmap bitmap = getBitmap(); return bitmap != null && !bitmap.isRecycled(); }
Android 3.0 及更高版本的内存管理
Android 3.0 (API Level 11) 引进了 BitmapFactory.Options.inBitmap 字段,如果设置了该属性,那么当使用了带有该 Options 参数的 decode 方法在加载内容时,decode 方法会尝试重用一个已经存在的位图。这就意味着位图内存已经被重用了,从而性能得到了改善,并且移除了内存的分配和解除分配。下面是一些使用 inBitmap 的注意事项:
・重用的位图大小必须和源位图大小相同(这样才能保证它们占用相同的内存),并且位图的格式应该是 JPEG 或 PNG(无论是作为资源形式还是数据流形式)。
・若设置了重用的位图的 Bitmap.Config 配置,则需要重写 inPreferredConfig 方法。
・你应该总是使用位图的解码方法,因为我们不能认为重用的位图是可用的(例如,若位图大小不匹配,就无法保证位图可重用)。
保存位图便于以后使用
如下的代码片断为你演示了位图是如何被保存便于以后使用的。当程序运行在 Android 3.0 或更高版本中时,位图将会从 LruCache 中被移除,指向该位图的 soft reference 将被存放在一个 HashSet 中,以便于之后在 inBitmap 中使用:
HashSet<SoftReference<Bitmap>> mReusableBitmaps; private LruCache<String, BitmapDrawable> mMemoryCache; // If you're running on Honeycomb or newer, create // a HashSet of references to reusable bitmaps. if (Utils.hasHoneycomb()) { mReusableBitmaps = new HashSet<SoftReference<Bitmap>>(); } mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) { // Notify the removed entry that is no longer being cached. @Override protected void entryRemoved(boolean evicted, String key, BitmapDrawable oldValue, BitmapDrawable newValue) { if (RecyclingBitmapDrawable.class.isInstance(oldValue)) { // The removed entry is a recycling drawable, so notify it // that it has been removed from the memory cache. ((RecyclingBitmapDrawable) oldValue).setIsCached(false); } else { // The removed entry is a standard BitmapDrawable. if (Utils.hasHoneycomb()) { // We're running on Honeycomb or later, so add the bitmap // to a SoftReference set for possible use with inBitmap later. mReusableBitmaps.add (new SoftReference<Bitmap>(oldValue.getBitmap())); } } } .... }
使用一个已经存在的位图
我们可以在程序中使用解码方法来判断是否有可重用的位图。例如:
public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeight, ImageCache cache) { final BitmapFactory.Options options = new BitmapFactory.Options(); ... BitmapFactory.decodeFile(filename, options); ... // If we're running on Honeycomb or newer, try to use inBitmap. if (Utils.hasHoneycomb()) { addInBitmapOptions(options, cache); } ... return BitmapFactory.decodeFile(filename, options); }
上述代码中的 addInBitmapOptions() 方法实现如下。该方法会查找一个已经存在的位图,将并该位图设置给 inBitmap 属性。注意,只有当找到了一个匹配的位图时(我们永远不能假定这种匹配一定能被找到),该方法才会为 inBitmap 赋值。
private static void addInBitmapOptions(BitmapFactory.Options options, ImageCache cache) { // inBitmap only works with mutable bitmaps, so force the decoder to // return mutable bitmaps. options.inMutable = true; if (cache != null) { // Try to find a bitmap to use for inBitmap. Bitmap inBitmap = cache.getBitmapFromReusableSet(options); if (inBitmap != null) { // If a suitable bitmap has been found, set it as the value of // inBitmap. options.inBitmap = inBitmap; } } } // This method iterates through the reusable bitmaps, looking for one // to use for inBitmap: protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) { Bitmap bitmap = null; if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) { final Iterator<SoftReference<Bitmap>> iterator = mReusableBitmaps.iterator(); Bitmap item; while (iterator.hasNext()) { item = iterator.next().get(); if (null != item && item.isMutable()) { // Check to see it the item can be used for inBitmap. if (canUseForInBitmap(item, options)) { bitmap = item; // Remove from reusable set so it can't be used again. iterator.remove(); break; } } else { // Remove from the set if the reference has been cleared. iterator.remove(); } } } return bitmap; }
最后,为了能给 inBitmap 赋值,我们还需要使用如下方法来判断是否有一个可选的位图满足指定的位图大小:
private static boolean canUseForInBitmap( Bitmap candidate, BitmapFactory.Options targetOptions) { int width = targetOptions.outWidth / targetOptions.inSampleSize; int height = targetOptions.outHeight / targetOptions.inSampleSize; // Returns true if "candidate" can be used for inBitmap re-use with // "targetOptions". return candidate.getWidth() == width && candidate.getHeight() == height; }
发表评论
-
[转] DialogFragment Fragment already added
2017-10-25 11:16 2594原文地址:http://blog.csdn.net/u0129 ... -
Android Studio .gitignore
2017-10-16 15:44 828参考文献: https://github.com/github ... -
[转] How to detect incoming calls in an Android
2017-10-13 14:14 1163原文地址:https://stackoverflow.com/ ... -
[转] Android 检测电源按钮是否被按下
2017-10-11 12:55 943原文地址:https://stackoverflow.com/ ... -
[原创] Android Activity onNewIntent() 详解
2017-08-16 13:46 4712阅读难度:中 阅读前提: 1. 需要了解 Android 的生 ... -
[转] Android Webview: “Uncaught TypeError: Cannot read property 'getItem' of null
2017-08-14 15:09 2233原文地址:https://stackoverflow.com/ ... -
[原创] 使用 Vitamio 播放视频作为 Splash 时出现失真情况的解决方案
2017-08-02 09:10 1172目前在做关于视频及流媒体播放项目时,有这样一个需求,应用启动时 ... -
[转] Android: Expand/collapse animation
2017-07-31 14:57 1531原文地址:https://stackoverflow.com/ ... -
[原创] Android ListView 在右上角添加三角形图标和文字
2017-07-26 17:24 2670最终显示效果如下图,在右上角添加三角形图标并在图标内显示文字: ... -
[转] Detect home button press in android
2017-07-20 17:49 1140原文地址:https://stackoverflow.com/ ... -
[原创] 开启 Android TextView Marquee
2017-07-18 15:47 1772亲测可能。直接上代码。 测试机器:XiaoMi 2S Andr ... -
[原创] 小米手机无法真机调试
2017-07-06 09:10 6447系统环境: 小米 2S MIUI 版本:8.0.1.0(LXA ... -
了解数据绑定 - Data Binding Library
2017-06-22 15:31 878原文地址: -
How to play gif with Fresco
2017-06-22 14:00 625原文地址:https://stackoverflow.com/ ... -
设置 Toolbar(ActionBar) 上的按钮颜色
2017-06-22 08:11 2029原文地址: https://stackoverflow.com ... -
Display back button on action bar and back event
2017-06-22 08:00 709原文地址: https://stackoverflow.com ... -
Gradle 修改 Maven 仓库地址
2017-06-02 15:51 1616修改 Gradle Maven 仓库地址为阿里云镜像 修改根 ... -
[转] How to clear cookies and cache of webview on Android when not in webview?
2017-04-26 09:28 2158原文地址:http://stackoverflow.com/a ... -
[转] Android 在程序中如何动态的修改程序图标
2017-03-02 17:05 877http://stackoverflow.com/a/4150 ... -
[转] Android Libraries
2017-01-16 10:28 531原文地址: https://dzone.com/article ...
相关推荐
android 多位图转化为单色位图。32位深图转1位深图。24位深转1位
----------------------------------- Android 编程基础 1 封面----------------------------------- Android 编程基础 2 开放手机联盟 --Open --Open --Open --Open Handset Handset Handset Handset Alliance ...
基于共享内存的位图,重点解释了为什么同步重要 GPU CUDA
vc中如何显示位图vc中如何显示位图vc中如何显示位图vc中如何显示位图vc中如何显示位图
能够在对话框的图片控件上显示位图 ,打开 ,连续显示,搜寻显示 ,单帧显示等
1:队列优先级 (如果想要listview中移动的区域优先被显示,而不是从上到下显示图片,可以把新建的任务提到任务队列前端) 2:实现了:中断任务的功能(比如进入一个Activity会开启大量任务,如果退出这个Activity ...
GlideBitmapPool, Glide位图池是用于重用位图内存的内存管理库 Glide位图池 Bitmap位图池Glide位图池是用于重用位图内存的内存管理库。 因为它重用位图内存,所以不再反复调用 GC,因此运行流畅的应用程序。 它使用...
恒率电源 WRD110S51-40W隔离式高效开关电源模块资料脚位图pdf,恒率电源 WRD110S51-40W隔离式高效开关电源模块资料脚位图
VC++源代码,根据位图实际大小,自动调整窗口大小,显示位图
关于如何使用android ndk在c中实现图像过滤器的android项目。
Android图片处理 从资源中获取位图,显示位图 图片缩略图显示,
资源中是一个vs2008sp1 IDE中VC++ MFC 图片控件(Picture Control)显示资源位图(BMP)、文件位图(BMP)、其它格式文件图片(JPG\PNG\BMP)的实例,可供参考。
这是一个用VC++6.0开发的图片显示程序,程序使用图片控件显示BMP位图资源,可以根据需要动态的修改要显示的图片。
位图的淡入淡出显示 位图像素透明 编译运行通过!
计算机软件-商业源码-实现位图显示特技.zip
VC读取并显示单色16色256色24位位图实例与图片。 花了两小时将其做出,以解我对真彩色以为类型位图加载显示的好奇。 2014年3月3日18:55:03
1位图文件的读取 2位图显示 3简单的图像处理;DCT 和中值滤波 4.DIB IP dibapi 文件有大量处理函数
android-tao-bitmap Android位图库。 变形金刚(制作为Builder)位图-旋转,翻转,调整大小,缩放,裁剪位图。 存在内存优化(默认情况下使用缓存文件)。 从视图转换位图。 使用遮罩创建形状的位图。
电信设备-一种基于Android内核的动态生成位图图像的信息显示方法.zip
商业编程-源码-位图的Alpha淡入淡出显示示例代码.zip