你真的知道怎么处理图片么?

准备工作

1.AllocationTracker的使用

2.Android中图片内存如何计算

3.图片占内存公式:分辨率 * 每个像素大小,严谨吗?
https://mp.weixin.qq.com/s/ufOjtKURP8QERWw1pn_m1Q

------------ 疑问----------------
实际使用AT抓取结果显示
测试机屏幕分辨率420dpi/xxh-dpi/2.625x
同一张1500*1004尺寸的png图,放在xxh-dpi文件夹下
8bit-color和24bit-color申请的内存均为4.62Mb左右。
也就说,位图深度是不影响的。
按照2里的公式
缩放尺寸 = 图片尺寸 / 当前图片文件夹代表的dpi * 目标机器屏幕的dpi + 0.5f 结果取整

scaledWidth = int( 1500 / 480 * 420 + 0.5f) = int(1313) = 1313

scaledHeight = int( 1004 / 480* 420 + 0.5f) = int(879) = 879

分配的内存理论值应当是
1313 * 879 * 4bytes /1024/1024= 4.403Mb
和实验值4.62Mb还是有一定误差的
误差问题暂且搁置。
---------------------分割线----------------------

正文

其实这个标题有点夸大,处理图片有很多的方式啦,
准确里说,总结的是:放一张图做background的时候,如何让内存分配最合理。

1.先放图

在之前的总结
AllocationTracker实践
以设置图片背景为例做了实践,
当时我们使用的方式就是
最偷懒最省事的 在某个layout.xml里background:@drawable
该方式最终调用
BitmapFactory.decodeStream()
这个时候,我们的dalvik虚拟机就会为此分配一块内存
newNonMovableArray,
这些都是AT给我们的信息。

乍一看,这都没有问题。

我准备了一张分辨率为7874*5315 的jpeg图,放在h-dpi里


OOM

/**测试机是6G的RAM,可用4G,largeHeap=false,所以这张大分辨率图放xh,xxh都能hold住。
理论值 int(7874 / 240 * 420+0.5) *(5315 / 240 * 420+0.5)=13780 * 9302 * 4 byte = 512891600 byte
实际信息显示申请分配 512671132 byte
*/

2.找调用

回归我们的重点,在xml中直接设置背景属性的做法应该是很普遍,但是这样面对不同配置的机器时,内存分配不合理,而且极易造成OOM,这是非常严重的问题。

通过AT和源码可知,xml配置background实质是在view init方法的中调用setBackground(Drawable)方法 or setBackgroundResource(Drawable)
他们最终都是调用到setBackgroundDrawable

xml配置背景的实质

依次调用setBackground方法

实际调用情况

通过我自己的代码实践,无论background是放图片drawable还是xml drawable,还是在drawable.xml里做很别扭的操作

普通状态是color,按下状态是图片

AT显示getDrawable占比非常大,依次跟踪追踪到ResourcesImpl::loadDrawable方法。

感觉像是在这里分配了内存,图片cache缓存起来供以后调用

3.猜测

1.加载图片最终都会调用BitmapFactory.decodeStream,直接走jni解析该图,分配的内存主要在工厂类初始化这里。
2.普通的方法setBackground,在除了decodeStream操作外,还会申请一部分内存块缓存这个Drawable,之后要用这个图,就直接从缓存里拿。
而这个就是内存爆炸的原因。

4.解决方案

知道原因后,我们的解决方法就是,直接调用工厂类解析目标图片供使用。
绕过分配内存缓存Drawble,从而减少OOM的风险,
在onDestroy的时候setBackground(null)显式解除引用,告诉gc可以回收。

直接调用图片工厂解析

参考:

以最省内存的方式读取本地资源的图片,存在bug:因机器分辨率不同而无法自动适配
* http://blog.csdn.net/woshicaixianfeng/article/details/6825295
* http://bbs.csdn.net/topics/390919272
图片的质量压缩和尺寸压缩
* http://blog.csdn.net/jdsjlzx/article/details/44228935
用decodeFileDescriptor替代decodeStream或者decodeFile
* http://www.th7.cn/Program/java/201606/888679.shtml
如何回收这些资源
* http://blog.csdn.net/springsky_/article/details/25212419
Drawable和Bitmap在内存中谁更省内存
* http://blog.csdn.net/zhu071011/article/details/48310597

其他的加载图片方案

1.Fresco
超大图和网络图推荐。小图不推荐,imagePepline比小图内存还多。
Fresco的内存管理
http://blog.csdn.net/sgwhp/article/details/49640611
http://www.cnblogs.com/wytiger/p/5690039.html

2.Glide
待续。。。

其余回收方案

回收TextView的Drawable资源

常常会出现一个textView上下左右某个方向接一张ImageView图
官方建议精简布局,推荐在textView的xml配置drawableLeft (someelse)
为了追求极致的资源回收,我们也应当在onDestroy对其进行回收
查看源码可知该attrribute

TextView在init时进行配置

实际调用的是

setCompoundDrawables

往下跟
真正设置的方法是setCompoundDrawables

也可以运用省内存方案加载图片。
解决方法
textView.setCompoundDrawablesWithIntrinsicBounds(null,null,null,null);
或者
textView.setCompoundDrawables(null,null,null,null);
理由见源码说明

(*^__^*) 嘻嘻

回收theme里的Background:Drawble资源

做过启动加速的朋友知道,在调起app时,会出现初始化加载的空白期,体现出来就是一块白屏。这个用户体验很不好。所以我们会在启动Activitiy的theme里
设置background,给用户一点击就打开的感觉。

启动加速的trick

我做了一个对照
avtivity的style放一张图,这个activity里的textView控件我也放一个style

两个style

AT抓取分配情况(点击查看大图)

上方的是activity的,下方是textView的

对activity的就是对ViewGroup里所有的view遍历set
下方textView的更简单,

调用view的init方法
setBackground

以上的分配套路和之前的分析一样。
那么问题来了,启动占位图,我们根本不想开辟一部分内存缓存这张图,
那如何省内存的去加载图片呢?

好的,为了更好的测试效果,我弄了一个OOM


activity的theme里放了一张超大的图

题外话:
catch 住 OOM,行吗?
https://mp.weixin.qq.com/s/83jlnS0-payhZoykr21Ohg

目前:
因为对activity启动了解不够,没懂整个view的绘制过程,暂未找到用省内存方案加载带图片的style/theme。

所以建议不加载带图片的style/theme,启动占位图也要及时回收。

回收方法,在super.onCreate之前,进行

getWindow.setBackgroundDrawble(null);

亲测生效的回收方案:
1.因为app启动的关系,在splashActivity的oncreate方法里去处理backgroud,不生效。即使是在super.onCreate()方法前调用getWindow.setBackgroundDrawble(null);

2.在super.onCreate()前调用setTheme(R.style.splash_no_bg)
不要直接setTheme(0),这样不生效,原因查看源码就知道了。
自定义的style_splash_no_bg的background属性用@null
再使用getWindow.setBackgroundDrawble(your drawble);
onDestroy里解除引用getWindow.setBackgroundDrawble(null);

踩坑记录:
因为使用了某第三方sdk,该sdk的初始化引用了splashActivity的context,
导致context一直被sdk的静态量一直引用,造成了内存泄漏10Mb--也就是这张bg_splash.jpg

简单来说就是
sdk引用context,context使用了theme,theme里有这张splash.jpg

最优解就是sdk解除context的引用,但是因为sdk的bug,目前无法做到。
那么我只能尽可能的减少泄漏值。

通过setTheme(R.style.splash_no_bg)方法解除大图片的引用。
可是因为业务的需要,splashActivity需要延迟1s才能到mainActivity(别问为什么,就是业务需求)
这就造成了1s的短暂白屏。
解决方案:

在onCreate()方法里依次调用
setTheme(R.style.splash_no_bg);
super.onCreate();
if(getWindow!=null)getWindow.setBackgroundResource(R.drawble.bg_splash);

在onDestroy()方法里
if(getWindow()!=null)getWindow.setBackgroudDrawable(null);解除引用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,357评论 0 17
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,432评论 25 707
  • 2021期待与你一起共事,点击查看岗位[https://www.jianshu.com/p/6f4d67fa406...
    闲庭阅读 16,606评论 0 75
  • 这是我从邻居那里听到的故事: 王大爷和老伴俩口子住在一个小区居民楼里,儿女们都在外地,平常也难得回来一次,平常就两...
    刘小松阅读 268评论 2 2
  • 刚刚看朗读者,没想到是最后一期了,还蛮不舍的,看到董卿最后回去的背影,多希望她再回头招招手,最后转身站在门后面时,...
    周洲的日常阅读 236评论 0 0