Magic Room

Android 史上最强图片面试

最近在做图片相关的需求,总结一下Android图片相关的知识,面试时将这些说
清楚基本就OK啦。感谢开源、Android开发艺术探索、相关优质博文。


一、图片处理背景知识

1.移动端运行可用内存限制(很早之前是单应用16MB)
2.超过限制引发问题:OOM(内存溢出)
3.引发思考:对图片进行压缩处理

二、图片压缩分类

  • 尺寸压缩
    概念:
    一般是根据控件大小进行比例压缩,被广泛使用的那一套流程,计算合适的采样率再去加载Bitmap到内存

    涉及知识点:
    1.压缩流程

    解码图片边缘拿到图片像素宽高           
    options.inJustDecodeBounds = true;
    计算压缩采样率   
    options.inSampleSize = calculateInSampleSize();     
    根据采样率压缩尺寸再去解码图片得到Bitmap
    options.inJustDecodeBounds = false;
    

    2.inSampleSize的正确计算姿势

    官方Demo里计算采样率可以满足大部分需求,但长宽比差距很大的图片就会有问题,推荐开源框架UIL里的处理方式
    区分图片的ScaleType
    
      int scale = 1;
    
      int widthScale = srcWidth / targetWidth;
      int heightScale = srcHeight / targetHeight;
    
      switch (viewScaleType) {
      case FIT_INSIDE:
          if (powerOf2Scale) {
              while (srcWidth / 2 >= targetWidth
                      || srcHeight / 2 >= targetHeight) { // ||
                  srcWidth /= 2;
                  srcHeight /= 2;
                  scale *= 2;
              }
          } else {
              scale = Math.max(widthScale, heightScale); // max
          }
          break;
      case CROP:
          if (powerOf2Scale) {
              while (srcWidth / 2 >= targetWidth
                      && srcHeight / 2 >= targetHeight) { // &&
                  srcWidth /= 2;
                  srcHeight /= 2;
                  scale *= 2;
              }
          } else {
              scale = Math.min(widthScale, heightScale); // min
          }
          break;
      }
    
      if (scale < 1) {
          scale = 1;
      }    
    

    3.拓展话题:ScaleType

    matrix(默认)   
    center  
    centerCrop
    centerInside     
    
    fitCenter
    fitEnd   
    fitStart   
    fitXY    
    

    4.误区盲点

    这种方式不一定会将图片字节大小降下去,有时把一张图片缩小一点点,图片本身所占内存反而增多了
    
  • 质量压缩
    概念:
    对图片的品质进行压缩,可以明显减少图片所占字节大小,例如微信分享限制缩略图大小不超过32KB

    压缩方法:

    1.读取Bitmap字节大小

    ByteArrayOutputStream baos = new ByteArrayOutputSream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//这里100的话表示不压缩质量
    long length=baos.toByteArray().length;
    

    2.降低品质进行压缩

    上面compress方法第二个参数的取值[1,100]
    一般80往下就压不动了,压缩算法不是按区间等分
    [80,100]之间较为明显

    涉及知识点:
    1.第一个参数区别

    Bitmap.CompressFormat.PNG
    Bitmap.CompressFormat.JPEG 
    

    2.第二个参数区间及含义

三、图片色彩样式

  • ALPHA_8
    每个像素只占1个字节,只能代表透明度,没有颜色属性

  • ARGB_4444
    每个像素要2字节,带透明度的颜色,官方不推荐使用了

  • ARGB_8888
    每个像素要4字节,带透明度的颜色

  • RGB_565
    每个像素要2字节,不带透明度的颜色

    涉及知识点:

    1.ARGB含义
    2.数字含义

    拓展:
    1.图片放在不同 drawable-*dpi下的区别
    2.为什么要美术切多套图或一套图?
    3.mipmap-*dpidrawalbe-*dpi区别

四、图片缓存

  • java中四种引用类型

    1.强引用
    2.软引用SoftReference
    3.弱引用WeakReference
    4.虚引用

  • 古老的方式

    二级缓存机制
    设置两个缓存池,一个强引用,一个软引用
    强引用作为一级缓存LinkedHashMap重写removeEldestEntry方法,删除最不常用对象

  • Android 3.0后的升级

    1.实践中软引用没啥卵用

    官方文档

    在实践中,软引用在缓存的处理上是没有效率的。运行时没有足够的信息用于
    判断哪些引用要清理回收还有哪些要保存。最致命的,当同时面对清理软引用
    和增加堆内存两种选择时它不知道做什么。对于你应用的每一个引用都缺乏有
    价值的信息,这一点限制了软引用让它的可用性十分有限。过早清理回收的引
    用导致了无必要的工作,而那些过晚清理掉的引用又浪费了内存。    
    

    2.引入LruCache

    近期最少使用算法,原理同LinkedHashMap逻辑,使用上要重写sizeOf()方法
    指定缓存计算大小的单位是字节,创建LruCache时传入总值一般为Runtime可用
    内存的1/8.

  • 常说的三级缓存

    1.流程

    加载一张图片,先从内存缓存中找,没有从磁盘缓存中找,再没有从网络下载   
    下载完后在两个缓存区分别保存一份,如果磁盘中有,就直接在内存缓存中保
    存一份    
    

    2.使用

    内存缓存 -> LruCache    
    磁盘缓存 -> DiskLruCache   
    

    3.网络异步下载,Handler切换线程,在UI线程设置

    4.优势:

    1.为用户节省流量  
    2.响应速度快,内存>磁盘>下载    
    
  • 自己打造ImageLoader

    1.图片的同步加载
    2.图片的异步加载
    3.图片的压缩处理
    4.内存缓存
    5.磁盘缓存
    6.网络下载图片(HttpUrlConnection 或网络框架 解耦和可配置)

  • 拓展

    在列表风格的控件加载图片时,通过监听滑动事件,当状态为Fling的时候停止加载
    在停下来的时候再去加载(照片墙 缓存策略使用 LIFO )
    开启硬件加速 android:hardwareAccelerated="true"

五、开源框架

  • 使用原则

    不要使用大而全的库,要选择专一功能的
    不要使用已经停止维护的
    调研包体大小和方法数,尽量轻量级
    二次封装,便于库的切换与调用

  • 截至2016.10.22开源库对比

    UniversalImageLoader
    老牌著名库,作者停止维护了,别用了

    xUtils3
    典型的大而全的库,依赖注入,DB,网络,图片,别用了

    Volley
    网络框架,同时也有和UIL类似的ImageLoader,包体和方法有限制可以采用
    但不支持加载本地图片,要自己修改,功能不强大

    Picasso
    JakeWharton大神的库,体积较小,无本地缓存,可结合Square全家桶OkHttp

    Glide
    Google推荐的图片库,支持GIF、WebP、Video多种媒体格式,网络配置可修改
    (默认UrlConnection 可结合Volley/OkHttp )色彩格式默认RGB565

    Fresco
    FaceBook搞的大东西,屌炸天但体积庞大,分分钟65K
    可参见廖祜秋大神的Fresco中文站点学习

  • 总结

    作为一名Google粉,目前项目以开发SDK为主,别想了,拥抱Glide…