一句话说透Android里面的Bitmap使用时应该注意什么

一句话总结:

用 Bitmap 就像搬砖------图片太大直接扛,内存分分钟爆缸!得学会"巧裁切、会缓存、勤回收",否则 App 卡崩没商量!


一、内存暴增,原地爆炸(OOM)

问题: 一张照片原图 4000x3000 像素 → ARGB_8888 格式占内存 48MB(4000x3000x4字节)!直接加载?低端机当场崩溃!

保命操作1:压缩到控件大小

kotlin 复制代码
// 先获取图片尺寸,不加载内存  
val options = BitmapFactory.Options().apply {  
    inJustDecodeBounds = true  
}  
BitmapFactory.decodeFile(path, options)  
val (width, height) = options.outWidth to options.outHeight  

// 计算缩放比例(目标控件大小 200x200)  
val inSampleSize = calculateInSampleSize(options, 200, 200)  

// 真正加载压缩后的图片  
options.inJustDecodeBounds = false  
options.inSampleSize = inSampleSize  
val bitmap = BitmapFactory.decodeFile(path, options) // 内存降到 200x200x4 ≈ 0.16MB!  

// 计算缩放比例的方法  
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {  
    val (width, height) = options.outWidth to options.outHeight  
    var inSampleSize = 1  
    if (height > reqHeight || width > reqWidth) {  
        val halfHeight = height / 2  
        val halfWidth = width / 2  
        while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {  
            inSampleSize *= 2  
        }  
    }  
    return inSampleSize  
}  

保命操作2:用低内存格式(有损画质)

ini 复制代码
options.inPreferredConfig = Bitmap.Config.RGB_565 // 每个像素占2字节(省一半内存!)  

二、不回收Bitmap,内存泄漏!

案例: 在 Activity 中加载 Bitmap 没回收 → Activity 销毁后 Bitmap 还在内存 → 反复打开关闭 → 内存泄漏!

解决:

  • Bitmap.recycle()(谨慎使用!):

    kotlin 复制代码
    override fun onDestroy() {  
        bitmap?.recycle() // 手动回收(注意:回收后不能再使用!)  
        bitmap = null  
        super.onDestroy()  
    }  
  • LruCacheGlide 自动管理:

    kotlin 复制代码
    // LruCache 示例(最大内存的1/8)  
    val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()  
    val cacheSize = maxMemory / 8  
    val bitmapCache = object : LruCache<String, Bitmap>(cacheSize) {  
        override fun sizeOf(key: String, bitmap: Bitmap): Int {  
            return bitmap.byteCount / 1024  
        }  
    }  

三、主线程加载大图,ANR 警告!

作死代码:

ini 复制代码
button.setOnClickListener {  
    // 直接在主线程加载大图 → 卡死5秒 → ANR!  
    val bitmap = BitmapFactory.decodeFile("sdcard/big_image.jpg")  
    imageView.setImageBitmap(bitmap)  
}  

保命操作:子线程加载 + 切主线程显示

scss 复制代码
// 用协程(Kotlin推荐)  
lifecycleScope.launch(Dispatchers.IO) {  
    val bitmap = loadBitmapFromFile("sdcard/big_image.jpg")  
    withContext(Dispatchers.Main) {  
        imageView.setImageBitmap(bitmap)  
    }  
}  

四、重复创建Bitmap,内存抖动!

案例: ListView/RecyclerView 的 getView() 里频繁 new Bitmap → GC 疯狂回收 → UI 卡顿!

解决: 用内存缓存 + 磁盘缓存 + 复用 ConvertView

kotlin 复制代码
// RecyclerView.ViewHolder 中复用 Bitmap  
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {  
    private var currentBitmap: Bitmap? = null  

    fun bind(imagePath: String) {  
        // 异步加载并复用 Bitmap  
        loadBitmapAsync(imagePath) { bitmap ->  
            currentBitmap?.recycle() // 释放旧的  
            currentBitmap = bitmap  
            itemView.imageView.setImageBitmap(bitmap)  
        }  
    }  

    fun clear() {  
        currentBitmap?.recycle()  
    }  
}  

五、终极保命指南

  1. 能缩则缩: 图片尺寸对齐控件大小,别加载原图!
  2. 能用缓存就别新建: LruCache、DiskLruCache 搞起来!
  3. 能异步就别阻塞主线程: 协程、RxJava、AsyncTask 任选!
  4. 能复用就别回收: ViewHolder 复用 Bitmap,减少GC压力!
  5. 能交给库就别自己写: Glide、Picasso 它不香吗?

口诀:
"大图不压必崩,复用缓存保命,
主线程里别硬刚,Glide一甩全搞定!"

(附:第三方库 Glide 的终极偷懒写法👇)

scss 复制代码
Glide.with(context)  
    .load("http://xxx.jpg")  
    .override(200, 200) // 强制缩放  
    .format(DecodeFormat.PREFER_RGB_565) // 低内存格式  
    .into(imageView)  
相关推荐
太空漫步112 小时前
android社畜模拟器
android
海绵宝宝_4 小时前
【HarmonyOS NEXT】获取正式应用签名证书的签名信息
android·前端·华为·harmonyos·鸿蒙·鸿蒙应用开发
凯文的内存6 小时前
android 定制mtp连接外设的设备名称
android·media·mtp·mtpserver
天若子6 小时前
Android今日头条的屏幕适配方案
android
林的快手8 小时前
伪类选择器
android·前端·css·chrome·ajax·html·json
望佑8 小时前
Tmp detached view should be removed from RecyclerView before it can be recycled
android
无限大69 小时前
算法精讲--动态规划四步法则
java·算法·程序员
xvch10 小时前
Kotlin 2.1.0 入门教程(二十四)泛型、泛型约束、绝对非空类型、下划线运算符
android·kotlin
人民的石头14 小时前
Android系统开发 给system/app传包报错
android
yujunlong391914 小时前
android,flutter 混合开发,通信,传参
android·flutter·混合开发·enginegroup