rokevin
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
  • Android 中 Bitmap 相关核心技术

  • 一、 Bitmap 基础核心技术
    • 1. Bitmap 实例的创建与销毁
      • (1) 实例创建的核心方式
      • (2) 销毁与内存释放
    • 2. Bitmap 像素配置(Bitmap.Config)
  • 二、 Bitmap 内存优化核心技术
    • 1. 解码优化(BitmapFactory.Options)
      • (1) 采样率优化(inSampleSize)
      • (2) 其他关键优化参数
    • 2. 内存缓存技术(LruCache)
    • 3. 磁盘缓存技术(DiskLruCache)
    • 4. 避免 Bitmap 内存泄漏
  • 三、 高效图片加载框架(基于 Bitmap 封装)
    • 1. Glide(推荐,Google 官方推荐)
    • 2. Picasso(Square 出品,简洁轻量)
    • 3. Fresco(Facebook 出品,高内存优化)
  • 四、 Bitmap 高级处理技术
    • 1. Bitmap 裁剪与缩放
    • 2. Bitmap 压缩(质量压缩 + 尺寸压缩)
      • (1) 质量压缩(compress())
      • (2) 尺寸压缩
    • 3. Bitmap 绘制与合成
  • 五、 关键注意事项与最佳实践
  • 总结
  • 资料

Android 中 Bitmap 相关核心技术

Bitmap 是 Android 中表示位图图像的核心类,用于存储图像的像素数据和相关属性,广泛应用于图片加载、显示、编辑等场景。围绕 Bitmap 的技术体系主要涵盖「基础操作、内存优化、图片加载与解码、高效显示、压缩与处理」等核心方向,以下是全面拆解:

一、 Bitmap 基础核心技术

1. Bitmap 实例的创建与销毁

(1) 实例创建的核心方式

Bitmap 无法直接通过 new 实例化,需通过以下 API 构建,核心分为「空位图创建」和「从资源 / 文件 / 流解码创建」:

  • 创建空位图(用于绘制编辑):

    // 核心 API:Bitmap.createBitmap() 系列方法
    val emptyBitmap = Bitmap.createBitmap(
        400, // 宽度(像素)
        400, // 高度(像素)
        Bitmap.Config.ARGB_8888 // 像素配置(关键,影响内存占用)
    )
    
  • 从资源解码创建(最常用):

    val resources = context.resources
    val bitmapFromRes = BitmapFactory.decodeResource(
        resources,
        R.drawable.test, // 资源 ID
        BitmapFactory.Options() // 解码配置(用于优化)
    )
    
  • 从文件 / 输入流解码创建:

    // 从文件解码
    val bitmapFromFile = BitmapFactory.decodeFile("/sdcard/test.jpg")
    // 从输入流解码(如网络请求返回的流)
    val inputStream: InputStream = getImageInputStream()
    val bitmapFromStream = BitmapFactory.decodeStream(inputStream)
    

(2) 销毁与内存释放

Bitmap 占用内存较大(尤其是高分辨率图片),需及时释放避免内存泄漏 / OOM:

  • 主动销毁:调用 bitmap.recycle(),释放 Bitmap 占用的原生内存(Native 内存),标记位图为「不可用」。

  • 辅助回收:将 Bitmap 引用置为 null,帮助 GC 回收 Java 层内存,配合 recycle() 使用:

    if (bitmap != null && !bitmap.isRecycled) {
        bitmap.recycle() // 释放 Native 内存
        bitmap = null // 释放 Java 层引用
    }
    
  • 注意事项:Android 3.0 以上,Bitmap 的 Native 内存由 ART 虚拟机统一管理,recycle() 不再是必须,但在大量处理图片时,主动调用仍能提升内存利用率。

2. Bitmap 像素配置(Bitmap.Config)

Bitmap.Config 决定了每个像素占用的内存大小,直接影响 Bitmap 的总内存开销(总内存 = 宽度 × 高度 × 每个像素字节数),是内存优化的关键:

配置类型每个像素字节数颜色精度适用场景内存占用(示例:400×400 位图)
ARGB_8888(默认)4 字节32 位真彩色(Alpha、Red、Green、Blue 各 8 位)对颜色精度要求高的场景(如相册、高清图片显示)400×400×4 = 640,000 字节(≈625KB)
RGB_5652 字节16 位彩色(Red 5 位、Green 6 位、Blue 5 位,无透明通道)无透明需求的场景(如普通背景、列表图片)400×400×2 = 320,000 字节(≈312KB)
ARGB_44442 字节16 位彩色(各通道均 4 位)低精度场景(已废弃,颜色失真严重)312KB(同 RGB_565)
ALPHA_81 字节仅保存透明通道,无颜色信息遮罩、透明效果处理160,000 字节(≈156KB)

优化建议:无透明需求时,优先使用 RGB_565,可减少 50% 内存占用。

二、 Bitmap 内存优化核心技术

Bitmap 是 Android 中 OOM(内存溢出)的高发源头,核心优化技术围绕「减少内存占用、避免内存泄漏」展开:

1. 解码优化(BitmapFactory.Options)

通过 BitmapFactory.Options 配置解码参数,避免解码高分辨率图片时占用过多内存,核心优化参数如下:

(1) 采样率优化(inSampleSize)

inSampleSize 是「缩放采样率」,表示解码时图片的宽高各缩小为原图的 1/inSampleSize,总内存缩小为 1/(inSampleSize²):

  • 规则:inSampleSize 必须是 ≥1 的整数,若传入非整数,会自动向下取整为 2 的幂(如 3→2、5→4)。

  • 使用步骤:

    fun decodeSampledBitmapFromRes(resources: Resources, resId: Int, reqWidth: Int, reqHeight: Int): Bitmap {
        // 步骤 1:设置 inJustDecodeBounds = true,仅获取图片尺寸,不加载像素数据
        val options = BitmapFactory.Options().apply {
            inJustDecodeBounds = true // 不分配内存,仅返回宽高信息
        }
        BitmapFactory.decodeResource(resources, resId, options) // 此时返回 null,仅填充 options 信息
        
        // 步骤 2:计算合适的 inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
        
        // 步骤 3:设置 inJustDecodeBounds = false,解码缩放后的图片
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeResource(resources, resId, options)
    }
    
    // 计算最优 inSampleSize
    fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        val (width: Int, height: Int) = options.outWidth to options.outHeight
        var inSampleSize = 1
        
        if (height > reqHeight || width > reqWidth) {
            val halfHeight = height / 2
            val halfWidth = width / 2
            // 找到最大的 inSampleSize(2 的幂),使得缩放后的宽高仍大于需求宽高
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2
            }
        }
        return inSampleSize
    }
    

(2) 其他关键优化参数

  • inPreferredConfig:指定解码后的像素配置(如 Bitmap.Config.RGB_565),减少内存占用。
  • inScaled:是否允许缩放(默认 true),配合 inDensity(原图密度)、inTargetDensity(目标密度)实现按密度缩放。
  • inPurgeable/inInputShareable:Android 低版本(❤️.0)用于允许 Bitmap 内存被系统回收,高版本已失效。

2. 内存缓存技术(LruCache)

利用「最近最少使用(LRU)」缓存策略,缓存已解码的 Bitmap,避免重复解码消耗内存和 CPU,核心使用 LruCache 类(Android 提供的 LRU 缓存实现):

class BitmapLruCache(context: Context) {
    // 步骤 1:计算可用缓存内存(一般取应用最大可用内存的 1/8)
    private val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
    private val cacheSize = maxMemory / 8
    
    // 步骤 2:初始化 LruCache,指定缓存大小,重写 sizeOf 方法计算每个 Bitmap 的大小
    private val bitmapLruCache = object : LruCache<String, Bitmap>(cacheSize) {
        override fun sizeOf(key: String, bitmap: Bitmap): Int {
            // 返回 Bitmap 占用的内存大小(单位:KB)
            return bitmap.byteCount / 1024
        }
    }
    
    // 缓存 Bitmap
    fun putBitmap(key: String, bitmap: Bitmap) {
        if (getBitmap(key) == null) {
            bitmapLruCache.put(key, bitmap)
        }
    }
    
    // 获取缓存的 Bitmap
    fun getBitmap(key: String): Bitmap? {
        return bitmapLruCache.get(key)
    }
    
    // 移除指定缓存
    fun removeBitmap(key: String) {
        bitmapLruCache.remove(key)
    }
    
    // 清空缓存
    fun clearCache() {
        bitmapLruCache.evictAll()
    }
}

3. 磁盘缓存技术(DiskLruCache)

配合内存缓存,将不常用的 Bitmap 缓存到磁盘(SD 卡),避免内存缓存被回收后重复从网络 / 资源解码,核心使用 DiskLruCache(Android 推荐的磁盘 LRU 缓存实现,需手动引入或自定义):

  • 核心作用:弥补内存缓存的不足(内存缓存有限,应用退到后台可能被系统回收)。
  • 适用场景:网络图片加载(如朋友圈、电商商品图片),缓存下载后的图片到本地。
  • 注意事项:磁盘读写耗时,需在子线程执行,避免阻塞主线程。

4. 避免 Bitmap 内存泄漏

  • 避免静态引用持有 Bitmap(静态引用生命周期与应用一致,无法被 GC 回收)。
  • Activity/Fragment 销毁时,及时回收 Bitmap(recycle() + 置为 null),清空缓存。
  • 列表(RecyclerView/ListView)中使用 Bitmap 时,复用 ViewHolder,避免创建过多 Bitmap 实例,且滑动时暂停图片加载。

三、 高效图片加载框架(基于 Bitmap 封装)

实际开发中,很少直接手动操作 Bitmap(繁琐且易出问题),更多使用成熟的图片加载框架,它们已封装了 Bitmap 的解码、缓存、优化等逻辑:

1. Glide(推荐,Google 官方推荐)

  • 核心优势:自动适配 Bitmap 内存优化、支持生命周期绑定(避免内存泄漏)、自动压缩、支持 GIF / 视频帧加载。

  • 简单使用:

    Glide.with(context)
        .load("https://test.com/test.jpg") // 图片资源(网络、本地、资源 ID)
        .placeholder(R.drawable.placeholder) // 占位图
        .error(R.drawable.error) // 错误图
        .override(400, 400) // 指定显示尺寸
        .into(imageView) // 显示到 ImageView
    

2. Picasso(Square 出品,简洁轻量)

  • 核心优势:API 简洁、自动内存 / 磁盘缓存、自动适配 ImageView 尺寸。

  • 简单使用:

    Picasso.get()
        .load("https://test.com/test.jpg")
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.error)
        .resize(400, 400)
        .into(imageView)
    

3. Fresco(Facebook 出品,高内存优化)

  • 核心优势:Bitmap 内存存储在 Native 层,避免 Java 层 OOM、支持渐进式加载、适合超大图片。
  • 适用场景:对内存要求极高的应用(如相册、图片编辑类 App)。

四、 Bitmap 高级处理技术

1. Bitmap 裁剪与缩放

  • 裁剪:使用 Bitmap.createBitmap()裁剪指定区域的像素:

    // 裁剪原图的 (100,100) 到 (300,300) 区域
    val croppedBitmap = Bitmap.createBitmap(
        originalBitmap,
        100, // 起始 X 坐标
        100, // 起始 Y 坐标
        200, // 裁剪宽度
        200  // 裁剪高度
    )
    
  • 缩放:使用 Matrix 配合 Bitmap.createBitmap() 实现任意比例缩放:

    fun scaleBitmap(originalBitmap: Bitmap, scale: Float): Bitmap {
        val matrix = Matrix().apply {
            postScale(scale, scale) // x、y 轴缩放比例
        }
        return Bitmap.createBitmap(
            originalBitmap,
            0,
            0,
            originalBitmap.width,
            originalBitmap.height,
            matrix,
            true // 是否过滤(抗锯齿,提升缩放后画质)
        )
    }
    

2. Bitmap 压缩(质量压缩 + 尺寸压缩)

(1) 质量压缩(compress())

  • 核心:降低图片的压缩比,减少文件大小,不改变 Bitmap 的像素尺寸和内存占用,仅影响输出的文件(如 JPG/PNG)大小。

  • 适用场景:图片上传(减少网络传输大小)。

    fun compressBitmapQuality(bitmap: Bitmap, outputPath: String): Boolean {
        val outputStream = FileOutputStream(outputPath)
        // 压缩格式:JPEG(支持有损压缩)、PNG(无损压缩,压缩无效)
        val result = bitmap.compress(
            Bitmap.CompressFormat.JPEG,
            80, // 压缩质量(0-100,100 为无压缩)
            outputStream
        )
        outputStream.close()
        return result
    }
    

(2) 尺寸压缩

  • 核心:通过缩小 Bitmap 的宽高,减少内存占用和文件大小(即前文的「采样率优化」)。
  • 适用场景:图片显示(如列表缩略图),既减少内存占用,也减少文件存储大小。

3. Bitmap 绘制与合成

通过 Canvas 将多个 Bitmap 合成,或在 Bitmap 上绘制文字、图形:

fun composeBitmap(bitmap1: Bitmap, bitmap2: Bitmap): Bitmap {
    // 创建空白位图作为画布
    val composeBitmap = Bitmap.createBitmap(
        bitmap1.width,
        bitmap1.height,
        Bitmap.Config.ARGB_8888
    )
    val canvas = Canvas(composeBitmap)
    
    // 绘制第一张位图(底层)
    canvas.drawBitmap(bitmap1, 0f, 0f, null)
    
    // 绘制第二张位图(上层,偏移 (50,50))
    canvas.drawBitmap(bitmap2, 50f, 50f, null)
    
    // 可选:绘制文字
    val paint = Paint().apply {
        textSize = 30f
        color = Color.WHITE
    }
    canvas.drawText("合成图片", 100f, 100f, paint)
    
    return composeBitmap
}

五、 关键注意事项与最佳实践

  1. 避免在主线程处理 Bitmap:解码、压缩、合成等操作耗时,应在子线程(如 AsyncTask、Coroutine)执行,避免卡顿。
  2. 适配不同分辨率设备:通过 DisplayMetrics 获取设备屏幕密度,合理缩放 Bitmap,避免图片拉伸 / 模糊。
  3. 监控 Bitmap 内存:使用 Android Studio Profiler 的「Memory」面板,监控 Bitmap 内存占用,排查 OOM 问题。
  4. 高版本适配:Android 8.0 以上限制后台进程访问 SD 卡,Bitmap 磁盘缓存需适配「分区存储」。
  5. 优先使用矢量图(VectorDrawable):对于简单图标,使用 VectorDrawable 替代 Bitmap,可自适应各种分辨率,且占用内存极小。

总结

Android 中 Bitmap 相关技术的核心逻辑是「高效加载、优化内存、安全使用」:

  1. 基础层:掌握 Bitmap 的创建、销毁、像素配置,是后续优化的基础。
  2. 优化层:通过解码采样、LruCache 缓存、避免内存泄漏,解决 OOM 问题。
  3. 应用层:使用 Glide/Picasso 等框架,简化 Bitmap 操作,提升开发效率。
  4. 高级层:掌握 Bitmap 裁剪、压缩、合成,满足复杂图片处理场景。

资料

  • 高效加载大型位图
  • android图片压缩质量参数Bitmap.Config RGB_565等的含义
  • android Canvas.drawBitmap 方法的理解
  • Android bitmap上面写字
  • Drawable与 Bitmap 转换总结
  • Android开发之图片压缩处理
  • android bitmap保存为file文件,并更新到图库
最近更新:: 2026/1/15 03:00
Contributors: luokaiwen, 罗凯文