• 【Glide 】框架在内存使用方面的优化


    BitmapPool

    接口定义

    public interface BitmapPool {
    
      long getMaxSize();
    
      void setSizeMultiplier(float sizeMultiplier);
    
      Bitmap get(int width, int height, Bitmap.Config config);
    
      Bitmap getDirty(int width, int height, Bitmap.Config config);
    
      void clearMemory();
    
      void trimMemory(int level);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Bitmap缓存池的接口,作用是复用Bitmap对象内存,当一个Bitmap不再被使用时,Glide会把Bitmap占用的内存放到缓存池中,当有相同参数的Bitmap需要创建时,优先从缓存池中请求内存,避免频繁分配内存。与Handler的Message对象复用思路一致。默认实现是LruBitmapPool,采用LRU原则控制缓存大小。

    put

    Glide中放入缓存池的时机,主要在两个地方:
    1、bitmap 被回收(recycle)
    2、bitmap作为临时变量,暂时为生成其他bitmap存储数据

    被回收容易理解,put调用通常位于recycle方法中:

    public class BitmapDrawableResource{
      
      @Override
      public void recycle() {
        bitmapPool.put(drawable.getBitmap());
      }
      
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    public class BitmapResource{
      
      @Override
      public void recycle() {
        bitmapPool.put(drawable.getBitmap());
      }
      
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    final class BitmapPreFillRunner implements Runnable {
    	
      boolean allocate() {
         bitmapPool.put(bitmap);
      }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    作为中间变量存储数据是指,当Glide获取了图片的原始数据,但是图片需要处理后,才能被使用,所以put调用常常位于数据解析后,但是被应用前的位置:

    public final class Downsampler {
    	//从inputStream解析数据
    	private Bitmap decodeFromWrappedStreams(...){	
    		bitmapPool.put(downsampled);
    	}
    
    	private static Bitmap decodeStream(...){
    		bitmapPool.put(options.inBitmap);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    public class StreamBitmapDecoder{
    	//从inputStream解析数据
    	public void onDecodeComplete(...){
    	  bitmapPool.put(downsampled);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public final class TransformationUtils {
    	//对图片进行变换
    	public static Bitmap circleCrop(...){
    		pool.put(toTransform);
    	}
    	//对图片进行变换
    	public static Bitmap roundedCorners(...){
    		pool.put(toTransform);
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    get

    get方法应用的地方集中在图片变换的步骤中:从缓存池获取bitmap内存,把最后需要使用的图片数据,放到bitmap中。

    public final class TransformationUtils {
    
       private static Bitmap drawToBitmap(){
    	      Bitmap result = bitmapPool.get(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
       }
    	
    
    	public static Bitmap circleCrop(...){
        	Bitmap result = pool.get(width, height, getNonNullConfig(inBitmap));
    	}
    
    	public static Bitmap centerCrop(...){
        	Bitmap result = pool.get(width, height, getNonNullConfig(inBitmap));
    	}
    
    	public static Bitmap rotateImageExif(...){
        	Bitmap result = pool.get(width, height, getNonNullConfig(inBitmap));
    	}
    
    	public static Bitmap fitCenter(...){
        	Bitmap result = pool.get(width, height, getNonNullConfig(inBitmap));
    	}
    
    	public static Bitmap roundedCorners(...){
    		pool.put(toTransform);
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    ArrayPool

    理解了BitmapPool,其实ArrayPool也差不多。Glide需要处理很多图片的数据,不可避免的要从InputStream中读取数据,这时候就要用到byte数组(byte[]),ArrayPool作用就是缓存byte数组,避免频繁创建对象。

    最后

    理解源码不是最终目的,纸上得来终觉浅,绝知此事要躬行,学习优秀的代码,最重要的是掌握其中的思想,并应用到自己的项目中。
    Glide的开发者们在一开始,一定没有想到内存方面的优化,而是通过性能分析,定位到这里,并提出这样一个解决方案。
    因此,必须掌握如何分析app内存:
    Android性能优化:使用Profiler进行内存优化

  • 相关阅读:
    企业微信应用开发
    CMU15445 (Fall 2019) 之 Project#4 - Logging & Recovery 详解
    每日一题 —— LC. 891 子序列的宽度之和
    vuex01
    Redis数据库的事物机制(详细讲解)
    【简单教程】利用Net2FTP构建免费个人网盘,实现便捷的文件管理
    语音信号处理-基础(五):傅立叶变换【离散傅里叶变换(DFT)、O(n^2)】【快速傅里叶变换(FFT)、O(nlogn)】、【短时傅里叶变换(STFT)】
    如何准确高效的对电商数据进行分析
    栈的基础函数介绍及用法
    Python学习基础笔记十四——函数参数
  • 原文地址:https://blog.csdn.net/qq_23049111/article/details/125305714