内存泄露分析,从此简单
--- 喜欢项目,喜欢分析内存泄露。
刚进入到项目不久(还未转正),测试还没给反馈之前,简单看一下项目的内存泄露情况吧。
1.首先引入LeakCanary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
2.重新构建APP,运行。
打开,每个Activity,Fragment,对话框,弹窗等等。过5分钟,从App附属的Leaks App内查看报告。
3.分析
我主要分析,这个ToastShow.mToastStrategy
先看代码,从代码去分析内存泄露情况。
class CustomSysToastStrategy : IToastStrategy {
private var mToast: ToastCompat? = null
fun show(context:Context){
cancel()
//系统toast采用依赖application防止内存泄漏
val appContext = context.applicationContext
val toastView = LayoutInflater.from(appContext).inflate(R.layout.toast_custom, null)
val tv = toastView.findViewById<TextView>(R.id.mCustomToastMessage)
tv.text = str
val baseToast = Toast(appContext)
baseToast.setGravity(Gravity.CENTER, 0, 0)
baseToast.duration = duration
baseToast.view = toastView
mToast = ToastCompat.makeText(appContext, baseToast)
mToast!!.show()
}
override fun cancel() {
if (mToast != null) {
mToast!!.cancel()
mToast = null
}
}
}
从代码得知,两个方法一个负责(show方法)展示Toast,一个负责回收(cancel方法)Toast。
先看show 方法。
第一行直接是cancel,为了防止多个Toast同时触发,可能会导致无限个Toast。
第二行:是为了全局能使用Toast(其实不需要).
第三行:从布局文件解析出一个View(toastView)
后面创建Toast对象(baseToast), ToastCompat (mToast),一个个的塞进去,俄罗斯套娃模式。
//其实一个对象就够了。
在cancel里面,取消Toast,把toast的引用指空。
问题在cancel这个方法里。
mToast=null
猜测:这步骤操作,只能去清空mToast, 但是还是不能解决toastView,baseToast的内存资源回收。
这一点从Leaks的报告里也能推导出。或者cancel方法内打印是否null的判断。
4.报告
Leaks的报告内容如下:
关键内容:android.widget.LinearLayout instance Leaking:YES
描述的是,LinearLayout 实例触发了View.onDetachedFromWindow()方法,但是无法被回收。
-
优化
思路是把分配的对象拉到方法外,在cancel里面进行null赋值回收资源。
private var toastView: View? = null
private var baseToast: Toast?=null
private var mToast: ToastCompat? = null
//...省略了部分代码。
override fun cancel() {
if (mToast != null) {
toastView=null
baseToast=null
mToast!!.cancel()
mToast = null
}
}
The end.