Android应用内存优化技巧踩坑记录
最近在优化一个Android应用的内存使用时,踩了不少坑,分享一下实战经验。
问题背景
项目中出现了频繁的OOM(Out of Memory)异常,特别是在图片加载和列表滚动时。通过Android Profiler分析发现,Bitmap内存占用过高,GC频繁触发。
踩坑过程
1. Bitmap内存泄漏
最初以为是图片加载的问题,但实际排查发现是Bitmap没有及时回收导致的内存泄漏。
错误代码:
// 这样做会导致内存泄漏
fun loadImage(url: String, imageView: ImageView) {
val bitmap = BitmapFactory.decodeStream(url.openStream())
imageView.setImageBitmap(bitmap)
}
正确做法:
fun loadImage(url: String, imageView: ImageView) {
// 使用WeakReference避免内存泄漏
val bitmap = decodeSampledBitmapFromResource(url, 100, 100)
imageView.setImageBitmap(bitmap)
// 及时回收
bitmap.recycle()
}
private fun decodeSampledBitmapFromResource(
resId: Int, reqWidth: Int, reqHeight: Int
): Bitmap {
// 首先设置inJustDecodeBounds为true来获取图片尺寸
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeResource(resources, resId, options)
// 计算缩放比例
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
options.inJustDecodeBounds = false
return BitmapFactory.decodeResource(resources, resId, options)
}
2. RecyclerView ViewHolder未正确复用
在列表数据更新时,没有及时清理ViewHolder中的资源。
踩坑代码:
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.imageView.loadImage(data[position].imageUrl)
// 没有清理之前的图片加载任务
}
优化方案:
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
// 清理之前的加载任务
holder.imageView.clear()
holder.imageView.loadImage(data[position].imageUrl)
}
// 在ViewHolder中添加清理方法
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun clear() {
imageView.setImageDrawable(null)
// 清理图片加载任务
}
}
3. 使用WeakReference处理监听器
在Activity/Fragment中注册了多个监听器,没有及时注销导致内存泄漏。
错误做法:
// 监听器持有Activity引用
button.setOnClickListener {
// 处理逻辑
}
正确方案:
private val clickListener = View.OnClickListener {
// 处理逻辑
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener(clickListener)
}
override fun onDestroy() {
super.onDestroy()
button.setOnClickListener(null)
}
总结
内存优化需要从多个维度入手,包括Bitmap处理、资源回收、监听器管理等。建议在开发过程中使用Android Profiler定期监控内存使用情况,及时发现问题。
关键点总结:
- Bitmap加载时注意缩放和回收
- RecyclerView ViewHolder及时清理资源
- 监听器注册后记得注销
- 使用WeakReference避免强引用
- 定期使用Profiler监控内存使用

讨论