一句话说透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)  
相关推荐
tinker43 分钟前
ROS2 - SLAM 同步定位与建图
程序员
molihuan4 小时前
开源 全平台 哔哩哔哩缓存视频合并 Github地址:https://github.com/molihuan/hlbmerge_flutter
android·flutter·缓存·ffmpeg·开源·github·音视频
奶糖 肥晨5 小时前
批量重命名技巧:使用PowerShell一键整理图片文件命名规范
android·服务器·数据库
Momentary_SixthSense5 小时前
如何对较长的Stream链进行Debug
android·java·开发语言
little_fat_sheep6 小时前
【Rive】rive-android源码分析
android
教程分享大师7 小时前
新魔百和m401h全部版本当贝桌面固件卡刷包和线刷包带adb权限
android
rufeii8 小时前
网鼎杯 2020 青龙组
android
我要升天!8 小时前
MySQL表的内连和外连
android·mysql·adb
dora8 小时前
Flutter中dart和原生代码的通信之MethodChannel
android·flutter
路上^_^9 小时前
安卓基础组件031-Retrofit 网络请求框架
android