Moosphan / Android-Daily-Interview

:pushpin:每工作日更新一道 Android 面试题,小聚成河,大聚成江,共勉之~

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

2019-08-01:如何处理大图的加载?

Moosphan opened this issue · comments

2019-08-01:如何处理大图的加载?

1.通过第三方软件加载。
2.通过压缩工具压缩。
3.加载缓存方式。

具体压缩工具,有哪些推荐的呢?大神

把图片处理成webp格式,或者用Luban压缩压缩图片

1、首先确定大图的用途,精度需求:
a)完整显示,对精度要求不高,图片本身就很大
b)对精度需求比较高,不需要完整显示
2、解决方案
a)针对第一种的处理图片本身,按需加载(根据显示设备本身大小进行缩放),降低精度加载(改变图片模式,如将ARGB8888改成RGB565,ARGB4444),修改图片格式(png改成webp,jpg)
b)第二种的一般采用局部加载,主要要用到的是BitmapRegionDecoder这个类decodeRegion的方法,读取图片指定大小的数据,然后通过移动来动态改变显示区域的图片

在项目中统一图片库,对不同性能的机型做好加载策略(使用不同的Bitmap.Config加载图片,不同的压缩程度)。
在加载图片后也不能放松警惕,需要对所有图片进行统一监控:
超大图监控
图片是否超过view宽高,消耗不必要的内存
对超大图进行局部加载 (楼上有对此对对策)
重复图片监控
在开发过程中使用hprof分析工具查找重复bitmao,对代码进行优化
图片总内存监控
对应用内图片总内存进行统计,根据应用使用环境排查隐患

上面总结的很好,我说一种应用场景下的解决方案。
recycleview 或者 listview 等列表页中加载大图,为防止,浏览卡顿以及OOM。所以:1、懒加载(延迟加载)+异步线程,并配合第三方图片框架(Glide、Picasso、Fresco等)、luban 压缩图片。
2、LruCache缓存机制读取图片 配合 第一步。

我也分享下:

  • 首先分清你要做什么,是否支持缩放。以此来确定图片的宽高。如果只是显示,没必要把图片宽高弄得太大,如果要做类似世界地图的效果,肯定是要移动和缩放的,这种一般图片宽高会比较大。然后我们分情况说。
    • 一般加载图片,宽高只要跟控件宽高差不多,甚至小一些都是可以的。
      • 图片尽量使用软引用,较大的图片可以通过bitmapFactory缩放后再使用,并及时recycler。
      • 加载巨图时不要使用setImageBitmap或setImageResourse或BitmapFactory.decodeResource,这些方法拿到的都是bitmap的对象,占用内存较大。可以用BitmapFactory.decodeStream方法配合BitmapFactory.Options进行缩放
    • 加载超大宽高的图片。这里我没做过,但是之前看过类似的效果,原理也简单的了解了一下。就是分区块加载,比如先加载其中的某一块,用户移动时再加载其他区块。网上有一个不错的库BitmapRegionDecoder。

首先确定需求是否大图可以缩放,如果需要缩放一般图片的宽高都会挺大,如果只是显示就没有必要弄得太大。

  1. 如果加载一般的图片,宽高就跟控件宽高差不多。
    i. 图片尽量使用软引用,较大的图片可以通过bitmapFactory缩放后在使用,并及时recycle。
    ii. 加载巨图时不要使用setImageBitmap或setImageResourse或BitmapFactory.decodeResourse,这些方法拿到的都是bitmap的对象,占用内存较大。可以用BitmapFactory.decodeStream方法配合BitmapFactory.Options进行缩放
  2. 加载超大宽高的图片就是分区加载,主要要用到的是BitmapRegionDecoder这个类decodeRegion的方法,读取图片指定大小的数据,然后通过移动来动态改变显示区域的图片

1.对于本地大图,可以将png格式的转化为webp格式的
2.对于网络大图,利用options对图片进行压缩,如果加载的图片很多,需要Lrucache对图片进行缓存处理
3.对于超大型图片,可以局部加载,当用户移动时,再去进行加载。

对于超大类型的图片如果要保证精度和体验,可以采用瓦片地图的方案。

先通过BitmapFactory.Options 设置inJustDecodeBounds 不占用内存来获取图片信息
判断是否为大图 根据使用场景计算缩放比较 inJustDecodeBounds设置为false 传递inSampleSize缩放比例压缩图片