07.Android之多媒体问题
目录介绍
- 7.0.0.1 加载bitmap图片的时候需要注意什么?为何bitmap容易造成OOM?如何计算Bitmap占用内存?
- 7.0.0.2 如何理解recycle释放内存问题?图片加载到内存其实有两部分数据,这是为何?
- 7.0.0.3 如何在不压缩图片的情况下加载高清大图?加载图的机制是什么,为何不会内存泄漏?
- 7.0.0.7 LRU算法的原理?核心思想是什么?如果缓存满了的话,什么方法来管理移除最近最少使用的item和添加新的item?
好消息
- 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!
- 链接地址:https://github.com/yangchong211/YCBlogs
- 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!所有的笔记将会更新到GitHub上,同时保持更新,欢迎同行提出或者push不同的看法或者笔记!
7.0.0.1 加载bitmap图片的时候需要注意什么?为何bitmap容易造成OOM?如何计算Bitmap占用内存?
- 注意问题
- 直接加载大容量的高清Bitmap很容易出现显示不完整、内存溢出OOM的问题,所以最好按一定的采样率将图片缩小后再加载进来
- 为减少流量消耗,可对图片采用内存缓存策略,又为了避免图片占用过多内存导致内存溢出,最好以软引用方式持有图片
- 如果还需要网上下载图片,注意要开子线程去做下载的耗时操作技术博客大总结
- 为何bitmap容易造成OOM
- 如何计算Bitmap占用内存
- 1.1 如何计算占用内存
- 如果图片要显示下Android设备上,ImageView最终是要加载Bitmap对象的,就要考虑单个Bitmap对象的内存占用了,如何计算一张图片的加载到内存的占用呢?其实就是所有像素的内存占用总和:
- bitmap内存大小 = 图片长度 x 图片宽度 x 单位像素占用的字节数
- 起决定因素就是最后那个参数了,Bitmap'常见有2种编码方式:ARGB_8888和RGB_565,ARGB_8888每个像素点4个byte,RGB_565是2个byte,一般都采用ARGB_8888这种。那么常见的1080*1920的图片内存占用就是:1920 x 1080 x 4 = 7.9M
- 1.2 上面方法计算内存对吗
- 我看到好多博客都是这样计算的,但是这样算对吗?有没有哥们试验过这种方法正确性?我觉得看博客要对博主表示怀疑,论证别人写的是否正确。更多详细可以看我的GitHub:https://github.com/yangchong211
- 说出我的结论:上面1.1这种说法也对,但是不全对,没有说明场景,同时也忽略了一个影响项:Density。接下来看看源代码。
- inDensity默认为图片所在文件夹对应的密度;inTargetDensity为当前系统密度。
- 加载一张本地资源图片,那么它占用的内存 = width * height * nTargetDensity/inDensity * nTargetDensity/inDensity * 一个像素所占的内存。
@Nullable
public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
@Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
validate(opts);
if (opts == null) {
opts = new Options();
} if (opts.inDensity == 0 && value != null) {
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
opts.inDensity = density;
}
} if (opts.inTargetDensity == 0 && res != null) {
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
} return decodeStream(is, pad, opts);
}
- 正确说法,这个注意呢?计算公式如下所示
- 对资源文件:width * height * nTargetDensity/inDensity * nTargetDensity/inDensity * 一个像素所占的内存;
- 别的:width * height * 一个像素所占的内存;
- 我看到好多博客都是这样计算的,但是这样算对吗?有没有哥们试验过这种方法正确性?我觉得看博客要对博主表示怀疑,论证别人写的是否正确。更多详细可以看我的GitHub:https://github.com/yangchong211
- 1.3 一个像素占用多大内存技术博客大总结
- Bitmap.Config用来描述图片的像素是怎么被存储的?
- ARGB_8888: 每个像素4字节. 共32位,默认设置。
- Alpha_8: 只保存透明度,共8位,1字节。
- ARGB_4444: 共16位,2字节。
- RGB_565:共16位,2字节,只存储RGB值。
- Bitmap.Config用来描述图片的像素是怎么被存储的?
- 1.1 如何计算占用内存
7.0.0.2 如何理解recycle释放内存问题?图片加载到内存其实有两部分数据,这是为何?
- 如何理解recycle释放内存问题?
- 在Android2.3.3(API 10)及之前的版本中,Bitmap对象与其像素数据是分开存储的,Bitmap对象存储在Dalvik heap中,而Bitmap对象的像素数据则存储在Native Memory(本地内存)中或者说Derict Memory(直接内存)中,这使得存储在Native Memory中的像素数据的释放是不可预知的,我们可以调用recycle()方法来对Native Memory中的像素数据进行释放,前提是你可以清楚的确定Bitmap已不再使用了,如果你调用了Bitmap对象recycle()之后再将Bitmap绘制出来,就会出现”Canvas: trying to use a recycled bitmap”错误,而在Android3.0(API 11)之后,Bitmap的像素数据和Bitmap对象一起存储在Dalvik heap中。
- 图片加载到内存其实有两部分数据,这是为何?技术博客大总结
- 一个图片加载到内存里,其实是有两部分数据组成,一部分是图片的相关描述信息,另一部分就是最重要的像素信息(这部分是有byte数组组成的),android系统为了提高对图片的处理效率,对于图片的处理都是调用了底层的功能(由C语言实现的),也就是说一个图片加载到内存里后是使用两部分的内存区域,简单的说:一部分是java可用的内存区,一部分是c可用的内存区,这两个内存区域是不能相互直接使用的,这个bitmap对象是由java分配的,当然不用的时候系统会自动回收了,可是那个对应的C可用的内存区域jvm是不能直接回收的,这个只能调用底层的功能释放。所以你要调用recycle方法来释放那一部分内存。
- 查看源码如下所示
- 翻译这段解释:释放bitmap内存的时候,它会释放和这个bitmap有关的native内存,同时它会清理有关数据对象的引用,但是这里处理数据对象的引用,并不是立即清理数据(他并不是调用玩recycle()方法,就直接清理这个内存,他只是给垃圾回收机制发送一个指令,让它在bitmap没有对象引用的时候,来进行垃圾回收)。当调用recycle()方法之后,这个bitmap就会被表明为“死亡状态”。这个时候你在调用bitmap其他相关的方法,例如果get像素()或set像素()就会抛出一个异常。同时这个操作是不可逆的,所以一定百分之百确定这个bitmap在以后的场景下,不会被你的程序在使用到,再去调用recycle()方法。所以谷歌源码中建议我们,可以不用去主动调用recycle()方法,因为在没有引用的情况下,我们的垃圾回收机制会主动的清理内存。
- 通过看源码,我们会发现,这个方法首先将这个Bitmap的引用置为null,然后调用了nativeRecycle(mNativeBitMap)方法,这个方法很明显是个JNI调用,会调用底层的c或者c++代码就可以做到对该内存的立即回收,而不需要等待那不确定啥时候会执行的GC来回收了。
7.0.0.3 如何在不压缩图片的情况下加载高清大图?加载图的机制是什么,为何不会内存泄漏?
- 如何在不压缩图片的情况下加载高清大图?
- 使用BitmapRegionDecoder,主要用于显示图片的某一块矩形区域,如果你需要显示某个图片的指定区域,那么这个类非常合适。
- 加载图的机制是什么,为何不会内存泄漏?
- 自定义可拖动的显示高清大图的View技术博客大总结
- 提供一个设置图片的入口,setInputStream里面去获得图片的真实的宽度和高度,以及初始化我们的mDecoder
- 重写onTouchEvent,在里面根据用户移动的手势,去更新显示区域的参数。在onMeasure里面为我们的显示区域的rect赋值,大小为view的尺寸
- 每次更新区域参数后,调用invalidate,onDraw里面去regionDecoder.decodeRegion拿到bitmap,然后draw。
7.0.0.7 LRU算法的原理?核心思想是什么,谈谈你的思路?
- 为减少流量消耗,可采用缓存策略。常用的缓存算法是LRU(Least Recently Used):
- 核心思想:当缓存满时, 会优先淘汰那些近期最少使用的缓存对象。主要是两种方式:
- LruCache(内存缓存):LruCache类是一个线程安全的泛型类:内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,并提供get和put方法来完成缓存的获取和添加操作,当缓存满时会移除较早使用的缓存对象,再添加新的缓存对象。
- DiskLruCache(磁盘缓存): 通过将缓存对象写入文件系统从而实现缓存效果
- 核心思想:当缓存满时, 会优先淘汰那些近期最少使用的缓存对象。主要是两种方式:
- 大概过程如下?技术博客大总结
- LruCache是android提供的一个缓存工具类,其算法是最近最少使用算法。它把最近使用的对象用“强引用”存储在LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前就从内存中移除。
- 如果缓存满了的话,什么方法来管理移除最近最少使用的item和添加新的item?
- trimToSize()方法,删除最年长的条目,直到剩余条目的总数达到或低于请求的大小
public void trimToSize(int maxSize) {
while(true) {
Object key;
Object value;
synchronized(this) {
if (this.size < 0 || this.map.isEmpty() && this.size != 0) {
throw new IllegalStateException(this.getClass().getName() + ".sizeOf() is reporting inconsistent results!");
} if (this.size <= maxSize || this.map.isEmpty()) {
return;
} Entry<K, V> toEvict = (Entry)this.map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
this.map.remove(key);
//计算现在缓存的大小,然后减掉多余的,内部调用的是sizeOf()方法
this.size -= this.safeSizeOf(key, value);
++this.evictionCount;
} //如果你想在在我们的缓存中实现二级缓存,可以实现此方法,源码中是空方法。
this.entryRemoved(true, key, value, (Object)null);
}
}
- trimToSize()方法,删除最年长的条目,直到剩余条目的总数达到或低于请求的大小
关于其他内容介绍
01.关于博客汇总链接
02.关于我的博客
- 我的个人站点:www.yczbj.org, www.ycbjie.cn
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yczbj/activities
- 简书:http://www.jianshu.com/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
- 开源中国:https://my.oschina.net/zbj1618/blog
- 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 邮箱:yangchong211@163.com
- 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
- segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e
07.Android之多媒体问题的更多相关文章
- Android官方多媒体API Mediacodec翻译(一)
因近期工作调整,关于Mediacodec部分的翻译会暂停,后续有时间一定补上,非常抱歉. 本文章为根据Android Mediacodec官方英文版的原创翻译,转载请注明出处:http://www.c ...
- Android的多媒体框架OpenCore介绍
网上资料很少, 不过还是找到一个比较详细的说明: 特地在此整理了下: 地址:http://blog.csdn.net/djy1992/article/details/9339787 分为几个阶段: 1 ...
- Android开发多媒体应用之SoundPool的使用的代码
内容过程中,把写内容过程中比较好的内容段记录起来,下面的内容是关于Android开发多媒体应用之SoundPool的使用的内容,希望对各位也有用途. public class MainActivity ...
- android之多媒体篇(一)
Android 4.0.3(Api Level 15)支持的多媒体格式. 注意:有些设备可能支持其他的文件格式. 1.Audio AAC LC/LTP.HE-AACv1(AAC+).AMR-NB.AM ...
- android之多媒体篇(二)
管理音频焦点 情景:当你的app隐退到后台,而其他也有播放能力的app浮现在前台,这个时候,你可能要暂停你原有app的播放功能,和解除监听Media Button,把控制权交给前台的APP. 这就需要 ...
- android之多媒体篇(三)
录像 Android提供了2种方案去录像. 方案一: 最简单的方式就是使用Intents去启动App来帮助你完成.这个方案使你能够指定输出的位置和视频的质量.这方案通常是最好的方法,应该可以用在多种情 ...
- Android之多媒体扫描过程
转自:http://blog.csdn.net/yan8024/article/details/6620359下面是系统图 MediaScannerReceiver会在任何的ACTION_B ...
- Android开发 多媒体提取器MediaExtractor详解_入门篇
前言 MediaExtractor字面意思是多媒体提取器,它在Android的音视频开发里主要负责提取视频或者音频中的信息和数据流(例如将视频文件,剥离出音频与视频).本章博客将讲解一些入门简单的东西 ...
- Android引用多媒体
res目录下,创建raw目录(Android会自动识别这个目录),如果自己创建的目录,可能无效底下的mp3格式,mp4格式的文件名必须小写. 引用方式: mediaPlayer = MediaPlay ...
- Android开发 多媒体提取器MediaExtractor详解_将一个视频文件分离视频与音频
前言 此篇博客讲解MediaExtractor将一个视频文件分离视频与音频,如果你对MediaExtractor还没有一个笼统的概念建议先了解我的另一篇入门博客:https://www.cnblogs ...
随机推荐
- List大陷阱,这个问题,造成我的很多问题,我靠,今天才发现MyList.Duplicates := dupIgnore;不sort就无效。
procedure TfrmMain.Button1Click(Sender: TObject); var MyLogisticsCompanyApi: TLogisticsCompanyApi; b ...
- Windows更换笔记本电脑需要迁移和删除的内容清单
一.需要迁移的内容清单 1.桌面和磁盘中重要的文件或者文件夹 2.chrome.Edge等浏览器的书签,可以导出 3.常用的软件安装包 (1).输入法(百度.或者搜狗) (2).浏览器(Chrome浏 ...
- C#开源免费的Windows右键菜单管理工具
前言 今天分享一个C#开源.免费.纯粹的Windows右键菜单管理工具:ContextMenuManager. 工具主要功能 程序支持国际化多语言显示. 启用或禁用文件.文件夹.新建.发送到.打开方式 ...
- JOISC 2022 记录
Day1 T1 Jail 操作很类似华容道.由于这题是可以树,同时每一个人走的都是最短路,这也就意味着不会出现通过好多个人一起的挪动来匀出空间. 所以如果合法,必然存在一种方案是每一次直接将一个人挪到 ...
- NC24949 [USACO 2008 Jan S]Running
题目链接 题目 题目描述 The cows are trying to become better athletes, so Bessie is running on a track for exac ...
- Android 自动化测试项目
1 前言 在 Android自动化测试框架uiautomator2详解 中,介绍了 uiautomator2 框架的环境配置.元素定位工具以及常用接口. 本文对 uiautomator2 框架 ...
- Vuex和普通全局对象
Vuex中的核心方法 Vuex是一个专为Vue.js应用程序开发的状态管理模式,其采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.每一个Vuex应用的核心就是 ...
- Annotation-specified bean name conflicts with existing
问题说明 Annotation-specified bean name conflicts with existing,non-compatible bean definition of same n ...
- Nologging到底何时才能生效
转了一篇EYGLE的文章 -------------------------------------------------- 最初的问题是这个帖子: http://www.itpub.net/sho ...
- Linux crontab不执行
Linux 系统里面计划任务,crontab 没有如期执行这是运维工作中比较常见的一种故障了. 下面结合最近部署自动脚本不执行问题排查步骤: 1.检查 crontab 服务是否正常 [dmdba@te ...