美文网首页
Bitmap优化

Bitmap优化

作者: 三十五岁养老 | 来源:发表于2022-03-07 21:02 被阅读0次

参考链接:https://juejin.cn/post/6844903919479422984

在日常开发的APP,大部分时候需要想用户展示图片信息,图片最终对应Android中的Bitmap对象。而对于APP端来说Bitmap又是一个比较麻烦的问题,主要表现在Bitmap是非常占用内存的对象,处理不当将导致APP运行卡顿甚至出现OOM


image.png

Android为每一个进程设置Dalvik Heap Size阈值,这个阈值在不一样的设备上会由于RAM大小不一样而各有差别。若是APP想要分配的内存超过这个阈值,就会发生OOM。
Android 5.x之前,Bitmap分配在Native heap中,而在,5.x-7.1,Bitmap分配在Dalvik或ART的Java heap中,Android 8.x之后,Bitmap分配在Native heap中

系统 native heap的增加并不受dalvik vm heapsize的限制,只要RAM有剩余空间,程序员能够一直在native heap上申请空间,固然若是 RAM快耗尽,memory killer会杀进程释放RAM。使用一些软件时,有时候会闪退,多是软件在native层申请了比较多的内存致使的。好比,UC web在浏览内容比较多的网页时闪退,缘由就是其native heap增加到比较大的值,占用了大量的RAM,被memory killer杀掉了。

Bitmap内存计算

从本地加载或者从网络加载可以用下面的公式计算:

图片的长度 * 图片的宽度 * 一个像素点占用的字节数

从资源文件夹加载:

Bitmap内存占用 ≈ 像素数据总大小 = 图片宽 × 图片高× (当前设备密度dpi/图片所在文件夹对应的密度dpi)^2 × 每个像素的字节大小

1、同一张图片放在不同的资源目录下,其分辨率会有变化。
2、Bitmap的分辨率越高,其解析后的宽高越小,甚至小于原有的图片(及缩放),从而内存也响应的减少。
3、图片不放置任何资源目录时,其使用默认分辨率mdpi:160。
4、资源目录分辨率和屏幕分辨率一致时,图片尺寸不会缩放。

优化思路

编码

android系统提供了四种编码格式


编码格式

其中,A代表透明度;R代表红色;G代表绿色;B代表蓝色。
ALPHA_8 表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度。
ARGB_4444 表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节。
ARGB_8888 表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节。
RGB_565 表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节。
可以通过改变图片格式,来改变每个像素占用字节数,来改变占用的内存
注意:由于ARGB_4444的画质惨不忍睹,一般假如对图片没有透明度要求的话,可以改成RGB_565,相比ARGB_8888将节省一半的内存开销。

采样

bitmap的占用内存是以bitmap的宽高和每个像素占用的字节数决定的,按公式我们可以缩减bitmap的宽高来达到压缩图片占用内存的目的

BitmapFactory.Options options = new BitmapFactory.Options();
    //不获取图片,不加载到内存中,只返回图片属性
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(photoPath, options);
    //图片的宽高
    int outHeight = options.outHeight;
    int outWidth = options.outWidth;
    Log.d("mmm", "图片宽=" + outWidth + "图片高=" + outHeight);
    //计算采样率
    int i = utils.computeSampleSize(options, -1, 1000 * 1000);
    //设置采样率,不能小于1 假如是2 则宽为之前的1/2,高为之前的1/2,一共缩小1/4 一次类推
    options.inSampleSize = i;
    Log.d("mmm", "采样率为=" + i);
    //图片格式压缩
    //options.inPreferredConfig = Bitmap.Config.RGB_565;
    options.inJustDecodeBounds = false;
    Bitmap bitmap = BitmapFactory.decodeFile(photoPath, options);
    float bitmapsize = getBitmapsize(bitmap);
    Log.d("mmm","压缩后:图片占内存大小" + bitmapsize + "MB / 宽度=" + bitmap.getWidth() + "高度=" + bitmap.getHeight());

缓存

内存缓存(LruCache)、磁盘缓存(DiskLruCache)
当我们首次从网络上或者USB读取图片,会对图片进行相应的压缩处理。在处理过后不加入缓存,下一次请求图片还是直接从网络上或者USB中直接读取,不仅消耗了用户的流量还重复对图片进行压缩处理,占用多余内存的同时加载图片也很缓慢。

目前的策略是内存缓存和存储设备缓存。当加载一张图片时,首先会从内存中去读取,如果没有就接着在存储设备中读,最后才直接从网络或者USB中读取

LruCache

LRU是用于实现内存缓存的一种常见算法,LRU也叫做最近最少使用算法,通俗来讲就是当缓存满了的时候,就会优先的去淘汰最近最少使用的缓存对象

private LruCache<Integer,Bitmap> mCache;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
 
        //1.初始化LruCache.
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        int cacheSize = maxMemory / 8;
        mCache = new LruCache<Integer,Bitmap>(cacheSize){
            @Override
            protected int sizeOf(Integer key, Bitmap value) {
                return value.getRowBytes() * value.getHeight() / 1024;
            }
        };
 
    }
 
    //2.从Cache中获取数据
    public Bitmap getDataFromCache(int key) {
        if (mCache.size() != 0) {
            return mCache.get(key);
        }
        return null;
    }
 
    //3.将数据存储到Cache中
    public void putDataToCache(int key, Bitmap bitmap) {
        if (getDataFromCache(key) == null) {
            mCache.put(key,bitmap);
        }
    }

DiskLruCache

磁盘缓存所使用的算法为DiskLruCache,它的使用比内存缓存要复杂一点,但是还是离不开上面的3步,初始化,查找和添加。同样的,

如何加载高清图

要求我们既不能压缩图片,又不能发生oom怎么办,这种情况我们需要加载图片的一部分区域来显示,通过BitmapRegionDecoder这个类,可以加载图片的一部分区域。

如何绕过dalvikvm heap size的限制 ?

  • 建立子进程,,内存分配按进程来。再使用进程通信,就能够把一些对象分配到新进程的heap上了,从而达到一个应用程序使用更多的内存的目的,固然,建立子进程会增长系统开销,并且并非全部应用程序都适合这样作,视需求而定。
    建立子进程的方法:使用android:process标签
  • 按不一样的系统版本,使用 jni 在native heap上申请空间

加载帧动画怎样避免OOM

原理

帧动画是按照一定的顺序播放一系列图片,从而产生动画。和我们看的动漫原理是一样的,本质上是对图片快速的翻页产生动的效果。系统 从xml中读取到图片id列表后就去硬盘中找这些图片资源,将图片全部读出来后按顺序设置给ImageView,利用视觉暂留效果实现了动画。

优化方案

一次拿出这么多图片,而系统都是以Bitmap位图形式读取的;而动画的播放是按顺序来的,大量Bitmap排好队等待播放然后释放,既然这么多Bitmap,一次却只能展示一个,纯属浪费资源,那么可以采取逐帧解析,及时回收。
参考链接:https://blog.csdn.net/u014702999/article/details/50544455

相关文章

  • 收集_Android源码文章

    一、Bitmap: Android bitmap压缩优化方案Android性能优化系列之Bitmap图片优化 二、...

  • 性能优化:Bitmap内存大小优化的几种常见方式

    性能优化:Bitmap内存大小优化的几种常见方式 Android中的bitmap是比较占用内存的,bitmap的大...

  • Bitmap

    获取Bitmap大小 Bitmap优化 一、主动释放Bitmap资源 二、主动释放ImageView的图片资源 三...

  • Android性能优化-Bitmap优化

    一、Bitmap质量压缩 二、Bitmap尺寸压缩 Bitmap优化加载的核心思想就是采用BitmapFactor...

  • Android性能优化之Bitmap加载优化

    目录 Bitmap优化 1.Bitmap.Config配置 这里我们用BitmapFactory.decodeRe...

  • Android性能优化

    Android性能优化包括布局优化、绘制优化、内存优化、线程优化、响应速度优化、Bitmap优化和ListView...

  • Android进阶之性能优化

    一、性能优化分类 布局优化 绘制优化 内存泄漏优化 响应速度优化 ListView优化 Bitmap优化 线程优化...

  • Bitmap

    Bitmap使用需要注意哪些问题 ? 要选择合适的图片规格(bitmap类型):通常我们优化Bitmap时,当需要...

  • Android Bitmap 到底占了多少内存

    前言 在Android的内存优化中,对Bitmap的优化绝对是主角,因为Bitmap对内存的影响很大,稍有不慎就很...

  • Android性能优化(五)之细说Bitmap

    在上一篇《Android性能优化(四)之内存优化实战》中谈到那个内存中的大胖子Bitmap,Bitmap对内存的影...

网友评论

      本文标题:Bitmap优化

      本文链接:https://www.haomeiwen.com/subject/olodrrtx.html