多dpi适配的新姿势


1. 简介

Android中经常要通过ImageView进行图片资源显示。在加载图片时,首先要考虑的两个因素就是体验问题和性能问题。

其中,体验问题是指图片显示的是否正确(例如Universal-Image-Loader在适配Adapter图片资源时会导致图片显示错位),图片显示尺寸是否合适,分辨率是否合适等。本文重点介绍ImageView加载图片中的显示问题。

2. 问题

在开发的过程中,一般会将不同分辨率的图片放置在不同的文件夹中,例如将三种同样内容不同分辨率的图片分别放置在drawable-xhdpi,drawable-xxhdpi和drawable-xxxhdpi中。那么,为什么要放置不同分辨率的图片,只放置一张对图片的显示有影响吗?本文中将对这个问题进行分析。

3. 概念描述

首先,图片对内存的占用是一个叠加的过程,也就是说图片资源不是及时释放的,使用过的图片在回收过程中可能会有一定程度的延迟。此外,很多时候图片所依附的Activity是出于当前Activity栈底的状态,再GC回收过程,这样的bitmap资源会被认为是活跃状态的,不会被Android系统回收。

另外一方面,Android中图片加载到内存中的内存占用跟图片的实际大小没有直接的关系,甚至于图片的实际像素尺寸也没有直接的关系。

在这里,首先要介绍几个概念:

  • 屏幕尺寸:指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米;
  • 屏幕分辨率:指在横纵向上的像素点数,单位是px,1px=1个像素点。一般以纵向像素*横向像素,如1960*1080;
  • 屏幕像素密度:是指每英寸上的像素点数,单位是dpi,即"dot per inch"的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小;
  • dp/dip:Density Independent Pixels, 密度无关像素的缩写;
  • px:像素,物理上的绝对单位
  • sp:Scale-Independent Pixels的缩写

一般而言,会有控件使用dp而文字使用sp的说法,但是也不尽然,sp会随着系统文字大小进行拉伸,而dp不会,再具体使用过程中还是要根据实际情况进行使用。

4. 多dpi适配

图像资源的多dpi适配,就是要在在不同的dpi文件夹中放置不同尺寸的图像资源,供设备自动跳转要显示的资源。以mdpi为尺寸基准1x,借一张很经典的图,多dpi适配可以表示如下:

图1. 多dpi资源适配

Android系统寻找图片的步骤是这样的:

  1. 去屏幕密度对应的目录去找。如果找到就拿来用。

  2. 如果没找到,就去比这个密度高一级的目录里面去找,如果找到就拿来用。

  3. 如果没找到就继续往上找。以此类推。

  4. 如果到了xxhdpi目录还没有找到的话,就会去比自身屏幕密度低一级的目录去找,如果低一级的目录>=hdpi,找到了就拿来用。

  5. 如果没找到,就去mdpi目录去找,如果找到了,就拿来用。

  6. 如果没找到,就去默认的drawble目录里去找,如果找到了就拿来用。

  7. 如果没找到,再去最低的ldpi目录里去找。如果找到了,就拿来用。

  8. 如果没找到,那就是没找到了,图片无法显示。(不过一般不会出现这种现象,因为如果每个目录都没有这个图片的话,你是编译不过的)

如果不是在对应目录里面找到的图片资源,要根据实际使用情况,进行显示,根据显示模式的不同,主要有以下两种情况:

(1). MeasureSpec.EXACTLY

这种情况下,图片的布局规则为match_parent或者是具体大小的数值(如layout_width =60dp, layout_height=60dp),这种情况下,图片的显示尺寸是固定的,所以显示的大小不会因为所在的资源文件夹dpi的不同而有所变化;例如图片A(尺寸60*60 大小2.02K)分别放置在xxhdpi文件夹和mdpi文件夹(Target Density),尺寸设置为layout_width =60dp, layout_height=60dp,显示分别如下:

   

(a). mdpi文件夹下的显示                                                  (b). xxhdpi文件夹下的显示

图2. Exactly模式下图像在不同Target Density下的显示

(2). MeasureSpec.AT_MOST

这种情况下,图片的布局规则为wrap_content。系统会根据图像内容的实际大小进行显示。同一张图片放在不同文件夹显示大小会有所不同,具体而言,同一张图像资源放置在mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi(Target Density)里面,显示的大小比较分别为:2:3:4:6:8

例如wrap_content布局下,分别将同一张图像A(尺寸60*60 大小2.02K)放置在xxhdpi和hdpi资源文件夹中,显示效果如下:

  

(a). hdpi文件夹下的显示                                           (b). xxhdpi文件夹下的显示

图3. At Most模式下图像在不同Target Density下的显示

      但是,在进行多dpi适配的时候,本身放置在mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi里面的图像资源尺寸比较就是2:3:4:6:8(Source Density),二者完美抵消,所以当前模式下,只放置一张合适尺寸的图像资源在一个合适的文件夹(Target Density)里面,不会影响不同尺寸设备的显示效果

例如wrap_content布局下,分别将分别将同一张图像A(尺寸60*60 大小2.02K)和图像B(尺寸30*30 大小2.02K)放置在xxhdpi和hdpi资源文件夹中,显示效果如下:

 

(a).图像资源A的显示                                                      (b). 图像资源B的显示

图4. At Most模式下图像在等比例Target Density和Source Density下的显示

5. 总结

在不同显示模式下,考虑到Exactly模式下图像资源的显示尺寸的固定性,以及At Most模式下Source Density和Target Density的抵消性,如果放置一张合适尺寸的图片资源在合适的文件夹,是可以实现不同设备的多dpi适配(显示的尺寸正常)。考虑到分辨率和使用率的问题,建议保留xxhdpi文件夹下的图像资源。

这种方法可以在只保留一种dpi尺寸图像的情况下,实现对不同机型的图像显示适配,从而可以有效的压缩apk的尺寸。结合之前的一篇博文《加载一张图片到ImageView到底占据多少内存》,可以发现只保留一份合适dpi的图像的情况下,运行过程中,加载图像到内存中的内存占用也是一样的。也就是说,在功能和性能上讲,只保留一种dpi的图像,是可以完成多dpi适配的。

但是,凡事都有但是。这种dpi适配的方式有两个问题:

(1). 只保留一张图片,在进行多dpi适配的时候,有可能会造成图像显示分辨率过低,导致体验性问题。这种情况,一般会在低dpi图像(Source Density)到高dpi机型(Target Density)适配的时候会出现;

(2). 在进行bitmap图像尺寸换算的时候,计算过程中,会造成内存和cpu的额外开销,这在低配机型上,有可能会在频繁地降采样过程中,导致OOM。

以上两点要重点关注。

当然,如果要是做某款特定机型的预制应用,那么,毫无疑问,直接保留一种dpi的图片资源。

6. 参考文献

  1. http://www.cnblogs.com/zhwl/archive/2013/06/12/3132722.html

  2. http://blog.csdn.net/skykingf/article/details/45536143

  3. http://www.itnose.net/detail/6614353.html

转载于:https://www.cnblogs.com/charles04/p/6914859.html

【原创】多dpi适配的新姿势相关推荐

  1. 一起解锁 GIL 的新姿势

    学 Python 的人有一个东西始终规避不开,那就是 GIL (Global Interpreter Lock).顾名思义,它使得任何时刻仅有一个线程在执行.即便在多核心处理器上,使用 GIL 的解释 ...

  2. 三种新姿势:帮你干掉过多的if-else

    点击上方"Java基基",选择"设为星标" 做积极的人,而不是积极废人! 每天 14:00 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java ...

  3. 要过年了,换个发微信红包新姿势

    苏生不惑第215篇原创文章,将本公众号设为星标,第一时间看最新文章. 关于微信之前写过好几篇文章了: 你刚才微信上撤回了什么?我都看到了 微信支付分开通了,来看看你有多少分 c 盘空间又满了?微信清理 ...

  4. 上班摸鱼又有了新姿势

    苏生不惑第287篇原创文章,将本公众号设为星标,第一时间看最新文章. 今天周末还要上班,下周就是7天国庆长假了,是不很期待了,这几天的主要任务就是摸鱼了,正好分享几个上班摸鱼的新姿势. 摸鱼玩游戏 之 ...

  5. 开门“新姿势”,商汤3D人脸识别智能门锁解决方案来了

    古文有云, "禹八年于外,三过其门而不入."--<孟子.滕文公上>,这是家喻户晓的大禹治水三过家门而不入的故事,今人皆叹大禹大公无私的奉献精神.其实,真实情况是这样的: ...

  6. 自动唤醒解锁电脑 bat_吉行贴士 | 一键解锁智能语音新姿势

    有时候爱死语音助理的便捷 有时候却又怪它的过分灵敏 语音助理表示 "怪我咯,反正怪我咯" 咱的语音助理为了给广大吉利车主们提供更贴心的服务,所以变得hin灵敏,你聊天中的一句&qu ...

  7. 免杀新姿势:利用线程将恶意代码注入到内存中

    本文讲的是免杀新姿势:利用线程将恶意代码注入到内存中, 产生存放远程攻击线程的进程 在这篇文章中我不想一步一步解释我编写的C#代码,但是我会展示下它能够绕过杀毒软件,并且操作非常简单,而且实用. 首先 ...

  8. JDK9新特性实战:简化流关闭新姿势

    转载自 JDK9新特性实战:简化流关闭新姿势. 做Java开发的都知道,每个资源的打开都需要对应的关闭操作,不然就会使资源一直占用而造成资源浪费,从而降低系统性能. 关于资源的关闭操作,从JDK7-J ...

  9. #开工新姿势#开启一年新征程,云社区叫你来充电啦!

    摘要:这有份开工红包等你来拿哟~~ 一年之计在于春 值此春暖花开.开学复工之季 华为云社区"内容共创计划"再次来袭! 无论你是正在读书的学生开发者,还是经验丰富的职场技术人,都非常 ...

最新文章

  1. 解读 | Arm 机器学习处理器的独特之处
  2. HDU2425:Hiking Trip(简单bfs,优先队列实现)
  3. exchange客户端不能正常登陆
  4. 每天一道LeetCode-----化简路径
  5. 【POJ - 2387】 Til the Cows Come Home(单源最短路Dijkstra算法)
  6. DHAT:动态堆分析工具
  7. 迪杰斯特拉c++_常用十大算法之 其九·迪杰斯特拉算法【日后详细补充】
  8. java高并发的经验
  9. 修改支付宝账号的授权方式
  10. linux同内核覆盖,Linux内核代码覆盖率 – GCOV
  11. 图像变换——对数变换
  12. s10_part3_django_ORM_查询相关_非常重要
  13. LeetCode链表简单题
  14. 9260ac网卡linux驱动,intel wireless-ac 9260 driver
  15. 谷歌浏览器安装 elasticsearch-head 插件
  16. win10系统无法开启远程服务器配置,win10系统无法连接远程服务器的方案介绍...
  17. 免费历史文献数字资源
  18. android 闪屏图片,Android的闪屏图像尺寸,以适应所有设备Android的闪屏图像尺寸,以适应所有设备(Andro...
  19. 鹏鹏:You have 14 unapplied migration(s). Your project may not work properly。。。。报错!
  20. 引入微信支付Java SDK WxPayAPI_JAVA.zip

热门文章

  1. SpringBoot自动化配置之一:SpringBoot内部的一些自动化配置原理
  2. COM 与 COM+ 区别
  3. [电子商务网站设计] 之 My Space
  4. 使用MFC里的类的方法
  5. 肖婧医生直播讲稿整理
  6. 用初中数学题理解SVM中不等式约束、拉格朗日乘子法、kkt条件、对偶
  7. 正则替换让一部分内容保持不变
  8. 基于水色图像的水质评价
  9. Hibernate的openSession和getCurrentSession区别
  10. 【转】vue项目打包上传的步骤和方法