`

use a recycled bitmap 的发现

 
阅读更多

 

    最近在做一个产品,里面有个用户指南的功能,该功能就是介绍怎么使用这个APP,然后是一个可以上下滚动的视图。其实就是一张图片。不过由于这张图片很大,所以用户退出这个界面的时候,必须回收资源。就是这个回收资源让我碰到了一问题。引发use a recycled bitmap的操作流程是这样子的,我进入Activity,然后得到图片并且显示出来, 退出时,在onDestroy()方法中recycle掉这个Bitmap对象。然后再次进入此界面,程序就爆了这个错误。

      先看关键代码:   在onCreate(Bundle)中

       

ImageView iv = (ImageView) findViewById(R.id.user_guide_iv);
Drawable draw = getResources().getDrawable(R.drawable.user_guide);
mUserGuideBmp = ((BitmapDrawable) draw).getBitmap();
iv.setImageBitmap(mUserGuideBmp);

 

            然后在 onDestroy()中回收资源
  

if (mUserGuideBmp!= null && !mUserGuideBmp.isRecycled()) {
	mUserGuideBmp.recycle();
	mUserGuideBmp= null;
}

 
    这些看起来都很正常,可是就是报错了。说我用了一个回收过的资源。难道我再次进入这个界面得到的还是我上次用的那个Bitmap的索引?如果是这样的,那么getResources().getDrawable()得到的也应该是我上次得到的Drawable了,因为我的Bitmap是该Drawable对象的成员变量。好吧,看getResources().getDrawable源码:

 

public Drawable getDrawable(int id) throws NotFoundException {
        synchronized (mTmpValue) {
            TypedValue value = mTmpValue;
            getValue(id, value, true);
            return loadDrawable(value, id);
        }
    }

 明显可以看出是是loadDrawable()方法得到Drawable对象,这个方法太多了,我们看下关键性的地方

 

 boolean isColorDrawable = false;
        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
                value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
            isColorDrawable = true;
        }
        final long key = isColorDrawable ? value.data :
                (((long) value.assetCookie) << 32) | value.data;

        Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);

        if (dr != null) {
            return dr;
        }

  可以看到有个getCachedDrawable(),看来第二次我们得到的Drawable对象是从缓存中得到的, 而缓存中的Drawable对象的成员变量Bitmap已经被我们给回收了,难怪会报错。知道原因了,就可以改了,我首先想到的清空下缓存,缓存没有了,Android应该会重新创建一个Drawable对象再加入缓存才对。由上面的方法可以看出缓存对象是mDrawableCache。那找下哪几个地方用到了mDrawableCache。不负众望,我在

public void updateConfiguration(Configuration config,DisplayMetrics metrics, CompatibilityInfo compat) 

方法中找到了

 clearDrawableCache(mDrawableCache, configChanges);

 这个方法明显是清空缓存的,从updateConfiguration的代码中可以看出,这个方法一定会被执行。那我们就在获取Drawable之前调用这个方法就可以了,试试

Configuration config = getResources().getConfiguration();
DisplayMetrics metrics = getResources().getDisplayMetrics();
getResources().updateConfiguration(config, metrics);

 其实我们并不是想要更改Configuration,所以传递给updateConfiguration方法的参数还是它原来的参数。

运行一下,报错,还是use a recycled bitmap的错误。晕,那好吧,看下clearDrawableCache方法

 private void clearDrawableCache(
            LongSparseArray<WeakReference<ConstantState>> cache,
            int configChanges) {
        int N = cache.size();
        if (DEBUG_CONFIG) {
            Log.d(TAG, "Cleaning up drawables config changes: 0x"
                    + Integer.toHexString(configChanges));
        }
        for (int i=0; i<N; i++) {
            WeakReference<Drawable.ConstantState> ref = cache.valueAt(i);
            if (ref != null) {
                Drawable.ConstantState cs = ref.get();
                if (cs != null) {
                    if (Configuration.needNewResources(
                            configChanges, cs.getChangingConfigurations())) {
                        if (DEBUG_CONFIG) {
                            Log.d(TAG, "FLUSHING #0x"
                                    + Long.toHexString(mDrawableCache.keyAt(i))
                                    + " / " + cs + " with changes: 0x"
                                    + Integer.toHexString(cs.getChangingConfigurations()));
                        }
                        cache.setValueAt(i, null);
                    } else if (DEBUG_CONFIG) {
                        Log.d(TAG, "(Keeping #0x"
                                + Long.toHexString(cache.keyAt(i))
                                + " / " + cs + " with changes: 0x"
                                + Integer.toHexString(cs.getChangingConfigurations())
                                + ")");
                    }
                }
            }
        }
    }

 

可以看到是下面这段代码才恩清空缓存

if (Configuration.needNewResources(
                            configChanges, cs.getChangingConfigurations())) {
                        if (DEBUG_CONFIG) {
                            Log.d(TAG, "FLUSHING #0x"
                                    + Long.toHexString(mDrawableCache.keyAt(i))
                                    + " / " + cs + " with changes: 0x"
                                    +           Integer.toHexString(cs.getChangingConfigurations()));
                        }
                        cache.setValueAt(i, null);
   } 

 

 那么

Configuration.needNewResources(configChanges,cs.getChangingConfigurations())

 方法就是判断你的配置是否改变了,可以发现配置没改变就不会清空缓存,看来android还是挺聪明的嘛。

可是我们不能为了清空缓存而去更改配置啊,那怎么办?

   突然发现我好傻,我得到Bitmap的方法换一种就可以了啊。我不要Drawable对象的成员变量保存的那个Bitmap就可以了啊。看下面获取Bitmap对象的方法:

Resources res = getResources();
Bitmap bmp = BitmapFactory.decodeResource(res, drawId);

 用这个方法获取的Bitmap对象跟上面的不同,它会每次都创建一个Bitmap对象,所以可以大胆的回收,程序通过,没问题。我可以深藏功与名啦

 

转载请注明出处:http://892848153.iteye.com/admin/blogs/2090216

 

 最后再记录一下关于图片的一些知识:

尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,

因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。

因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,

decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,

无需再使用java层的createBitmap,从而节省了java层的空间。

根据Android版本的不同,bitmap data存放的位置是不同的,3.0以前是分配在native heap上,3.0以后是分配在VM heap上。要想把图片放在native heap里面只要使用BitmapFactory.decodeStream方法解析出Bitmap就可以了。

Bitmap类的构造方法都是私有的,所以开发者不能直接new出一个Bitmap对象,只能通过BitmapFactory类的各种静态方法来实例化一个Bitmap。仔细查看BitmapFactory的源代码可以看到,生成Bitmap对象最终都是通过JNI调用方式实现的。所以,加载Bitmap到内存里以后,是包含两部分内存区域的。简单的说,一部分是Java部分的,一部分是C部分的。这个Bitmap对象是由Java部分分配的,不用的时候系统就会自动回收了,但是那个对应的C可用的内存区域,虚拟机是不能直接回收的,这个只能调用底层的功能释放。所以需要调用recycle()方法来释放C部分的内存。从Bitmap类的源代码也可以看到,recycle()方法里也的确是调用了JNI方法了的。(这些都是网络上的帖子,待验证)

分享到:
评论

相关推荐

    android截屏功能demo

    4. **转换为Bitmap**:将帧缓冲数据转换为Android系统的Bitmap对象,这可以通过创建一个新的Bitmap并设置其像素数据来完成。 5. **保存截屏图片**:最后,可以将Bitmap对象保存为JPEG或PNG格式的图片文件到用户的...

    辩证法在处理形而上学的“同一性”问题时有何独特之处?辩证法与传统逻辑和本体论有何根本性的差异?.pdf

    辩证法在处理形而上学的“同一性”问题时有何独特之处?辩证法与传统逻辑和本体论有何根本性的差异?

    cmd脚本-bat批处理-jscript-drivesInfoJS.zip

    cmd脚本-bat批处理-jscript-drivesInfoJS.zip

    cmd脚本-bat批处理-7.IF-ERRORLEVEL.zip

    cmd脚本-bat批处理-7.IF-ERRORLEVEL.zip

    cmd-bat-批处理-脚本-7.IF-ERRORLEVEL.zip

    cmd-bat-批处理-脚本-7.IF-ERRORLEVEL.zip

    深度学习中基于雷达和PPG数据的生命体征信号提取及四种神经网络模型应用

    内容概要:本文探讨了利用深度学习技术从雷达和PPG(光电容积脉搏波)数据中提取生命体征信号的方法。文中详细介绍了四种不同的神经网络模型:纯CNN、带有残差结构的ResNet、LSTM以及Transformer变体。每种模型都针对特定的数据特点进行了优化,如CNN适用于处理频谱图的时空特征,而LSTM则擅长捕捉时序动态。此外,还提供了数据预处理方法,包括短时傅里叶变换(STFT)、幅度归一化等。通过对这些模型的实际测试,作者分享了它们各自的优缺点及应用场景。 适合人群:对深度学习和生物医学工程感兴趣的科研人员和技术开发者,尤其是那些希望将深度学习应用于生命体征监测领域的研究人员。 使用场景及目标:① 使用深度学习技术从雷达和PPG数据中提取生命体征信号;② 探索并比较不同神经网络模型的效果;③ 提供实用的代码片段和数据预处理方法,帮助读者快速上手。 其他说明:本文不仅提供了理论分析,还包括具体的代码实现,使读者能够更好地理解和应用所介绍的技术。同时,作者还分享了自己的实践经验,为后续的研究提供了宝贵的参考。

    Amesim在HEV热管理和电池热管理中的应用及大厂培训模型解析

    内容概要:本文详细介绍了Amesim这款工程仿真软件在混合动力电动汽车(HEV)热管理和电池热管理中的应用。首先强调了Amesim学习资料的重要性,它能帮助工程师掌握建模、仿真和分析能力。接着阐述了大厂提供的Amesim培训模型优势,如资深工程师指导、结合实际案例等。最后深入探讨了HEV热管理及电池热管理的学习资料,涵盖基本原理、组成部件、工作过程、优化策略和技术应用案例等内容。 适合人群:对汽车工程尤其是混合动力电动汽车热管理系统感兴趣的工程师、研究人员及学生。 使用场景及目标:①希望通过Amesim提高自身建模和仿真实践能力的人群;②希望了解HEV热管理和电池热管理核心技术及其应用场景的技术爱好者。 其他说明:鼓励读者积极参与到Amesim的学习中来,利用大厂提供的优质培训资源,紧跟行业发展步伐,共同推动汽车工程技术进步。

    基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)

    基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计),个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的学生和需要项目实战练习的学习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,如果有需要的话可以放心下载使用。 基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分毕业设计)基于Python实现的手写数字识别代码和论文报告文档(高分

    校园二手交易平台数据库课程设计及数据库创建代码

    在 IT 领域,数据库设计是开发复杂系统的关键环节,校园二手交易平台项目就是一个典型案例。该项目通过实际应用数据库技术,帮助学习者将理论知识转化为实践能力。校园二手交易平台包含用户注册、商品发布、交易管理、评价系统等多个功能模块,这些模块都需要与数据库交互,存储和检索大量数据。因此,数据库设计必须确保数据的一致性、完整性和高效性。 项目的核心文件是“cj.sql”,这是一个 SQL 脚本文件,用于在 MySQL 数据库中创建表结构。文件中包含一系列的 CREATE TABLE 语句,定义了用户表(user)、商品表(product)、交易表(transaction)等表格。例如,用户表包含用户 ID、用户名、密码、联系方式等字段,商品表包含商品 ID、商品名、价格、描述等信息。为保证数据一致性,用户表通常设置主键约束(如用户 ID),确保每个用户有唯一标识。密码字段可能经过加密处理,以保护用户隐私。此外,商品表中可能设置外键约束,如用户 ID,引用用户表的主键,表示商品所属用户。 项目源码压缩包为“sms.rar”,解压后可导入 Eclipse 开发环境。开发者可能使用了 Spring Boot、MyBatis 等框架,通过 ORM 技术将 Java 对象与数据库表对应,简化数据库访问复杂性。运行项目前,需在 MySQL 中导入“cj.sql”文件,创建并初始化数据库,并在用户表中插入至少一条管理员账号记录,以便后续测试和管理。这一步体现了数据库初始化过程,是项目运行的必要条件。 该数据库课程设计项目不仅涵盖数据库基础知识,如表设计、SQL 语法,还涉及 Web 应用开发和数据库操作实践。通过该项目,学生能够深入理解数据库在实际应用中的重要性,提升数据库设计和编程能力,同时学会将数据库与后端开发紧密结合,实现数据的有效管理和高效利用。

    西门子S7-200PLC与MCGS组态在糖果包装控制系统中的应用及优势 PLC

    内容概要:本文介绍了西门子S7-200PLC(可编程逻辑控制器)和MCGS(人机界面)组态软件在糖果包装控制系统中的应用。S7-200PLC以其高可靠性和灵活性,实现了物料输送、包装机运行、封口等控制逻辑;MCGS组态软件则提供了实时监控和友好的人机交互界面,使操作员能方便地调整参数和查看设备状态。两者结合提高了生产效率,确保了产品质量的稳定性和安全性。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是关注PLC和HMI集成应用的专业人士。 使用场景及目标:适用于需要提升生产线自动化水平的企业,特别是食品加工行业。主要目标是优化生产流程,提高生产效率,保障产品品质。 其他说明:文中详细阐述了S7-200PLC的功能特点以及MCGS组态软件的操作方法,强调了两者的协同作用对于现代制造业的重要性。

    cmd-bat-批处理-脚本-mshta-btoa.zip

    cmd-bat-批处理-脚本-mshta-btoa.zip

    柔性作业车间调度问题经典算例汇总

    柔性作业车间调度问题(FJSP)是生产计划与控制领域的一个关键研究方向,主要研究如何在多台不同加工能力的机器上高效安排一系列作业,以实现最小化总体完工时间、最大完工时间等优化目标。资料中的“柔性作业车间调度算例汇总(FJSP算例).zip”文件包含了三个主要数据集,用于测试和验证调度算法。其中,Brandimarte_DATA 数据集由 Brandimarte 提供,包含多种规模和复杂性的 FJSP 实例,涵盖作业工序顺序、加工时间及机器分配等信息,可用于分析调度策略在实际生产中的表现,评估算法效率与适用性。DAUZERE_DATA 数据集由 Dauzère-Pérès 提供,包含更具挑战性的实例,涉及非均匀机器能力、加工时间不确定性等因素,有助于测试算法的鲁棒性和适应性。Hurink_DATA 数据集由 Hurink 等人创建,包含更复杂情况,如优先级约束、资源限制或时间窗口等,可用于评估算法在复杂约束下的性能。这些数据集常用于比较和评估新调度算法。研究者解析数据后,运用算法生成调度方案,并与最优解(若已知)对比,以评估算法效果。它们也用于基准测试,确保新算法性能至少与现有方法相当或更优。通过对这些数据集的分析和实验,可探索如遗传算法、模拟退火、粒子群优化、启发式算法及混合整数线性规划等多种调度策略,还可了解实际生产中哪些因素对调度结果影响最大,从而优化生产流程、提高效率。在 FJSP 研究中,理解数据集特点、构建合适模型、设计有效求解算法及严谨评估结果是重要步骤,这些实例为学者和工程师提供了实践与创新平台,推动了 FJSP 领域的理论发展和实际应用。

    cmd-bat-批处理-脚本-图像处理-stamp.zip

    cmd-bat-批处理-脚本-图像处理-stamp.zip

    基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告

    基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告,个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的学生和需要项目实战练习的学习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,如果有需要的话可以放心下载使用。 基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库及实验报告基于Java Swing的酒店信息管理系统的源代码、数据库

    响应式SEO教程资讯类网站pbootcms模板 SEO博客优化网站源码下载

    PbootCMS内核开发的网站模板,该模板适用于seo优化网站、seo博客网站等企业,当然其他行业也可以做,只需要把文字图片换成其他行业的即可; 自适应手机端,同一个后台,数据即时同步,简单适用!附带测试数据! 友好的seo,所有页面均都能完全自定义标题/关键词/描述,PHP程序,安全、稳定、快速;用低成本获取源源不断订单! 后台:域名/admin.php 账号:admin 密码:admin 模板特点 1:手工书写DIV+CSS、代码精简无冗余。 2:自适应结构,全球先进技术,高端视觉体验。 3:SEO框架布局,栏目及文章页均可独立设置标题/关键词/描述。 4:附带测试数据、安装教程、入门教程、安全及备份教程。 5:后台直接修改联系方式、传真、邮箱、地址等,修改更加方便。

    三菱PLC与组态王在蜂窝煤生产线控制系统的应用及其实现 工业自动化

    内容概要:本文详细介绍了三菱PLC和组态王在蜂窝煤生产线控制系统中的应用。首先,文章概述了蜂窝煤生产线的特点及其对自动化控制的需求。接着,分别阐述了三菱PLC在数据采集与处理、逻辑控制和通信接口方面的应用,以及组态王在界面展示、远程控制和数据存储与分析的功能。最后,通过一段伪代码展示了三菱PLC的基本控制逻辑,并强调了系统维护和升级的重要性。文章指出,这两项技术的应用显著提升了生产线的自动化水平,提高了生产效率和质量,降低了人工成本和安全风险。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对PLC编程和组态软件有一定了解的专业人士。 使用场景及目标:适用于希望深入了解三菱PLC和组态王在实际生产线中应用的读者,旨在帮助他们掌握这两种技术的具体实现方式,提升生产线的自动化水平。 其他说明:随着工业自动化技术的发展,未来的生产线控制系统将更加智能化、网络化和信息化。文中提到的内容为当前技术水平下较为成熟的应用案例,可供相关从业人员参考和借鉴。

    光储直流微电网下垂控制与母线电压分层管理策略研究 母线电压分层控制 v3.5

    内容概要:本文详细探讨了光储直流微电网系统中的下垂控制与母线电压分层控制策略。系统主要由150kW的光伏发电设备、50kW的储能装置以及100kW的并网变换器组成。储能装置在并网运行时作为负载运行(可充电),而在孤岛运行时作为电源运行。并网变换器和逆变器根据负载情况自动实现下垂模式和恒压模式切换,确保母线电压在不同模式下保持稳定。母线电压分层控制系统能够根据实际运行情况自动调整电压,维持系统的稳定运行。 适合人群:从事电力系统、新能源技术和微电网研究的专业人士和技术人员。 使用场景及目标:适用于光储直流微电网的设计、建设和运维阶段,旨在提高系统的效率和稳定性,确保在并网和孤岛两种模式下都能可靠运行。 其他说明:文中还介绍了不同电压模式的具体范围及其对系统的影响,并引用相关文献支持研究结论。

    基于MATLAB遗传算法的公交路线优化研究

    我最近开发了一个基于遗传算法的公交车路线规划程序,如果你对这个话题感兴趣,欢迎私信我了解更多详情。

    cmd-bat-批处理-脚本-backbat2.zip

    cmd-bat-批处理-脚本-backbat2.zip

    3D视觉测量与检测软件系统:工业自动化领域的深度检测利器

    内容概要:本文详细介绍了专为工业自动化领域设计的3D视觉测量与检测软件系统。该软件采用纯底层代码开发,适配多种3D线激光轮廓仪和其他3D相机,具备成像接口、渲染、可视化、流程控制、滤波处理、多种测量工具、逻辑工具、通信工具以及代码生成的UI界面等功能。尽管存在一些bug,但经过多年打磨已在不同客户的工业环境中稳定运行。软件具有高度的可扩展性和灵活性,可根据不同需求进行定制化开发。 适合人群:具备一定C++基础的开发人员,尤其是从事工业自动化测量与检测工作的工程师。 使用场景及目标:适用于工业自动化生产线中的高精度、高速度测量与检测任务,帮助企业和开发者降低项目成本并提升效率。目标是为用户提供一套完整的、可定制化的3D视觉测量与检测解决方案。 其他说明:文中提到的部分功能可能未完全展示,具体应用时可能会有所调整或新增功能。

Global site tag (gtag.js) - Google Analytics