场景
在MainActivity中分别加载两个Fragment处理业务。 首先触发加载SecondFragment:
//MainActivity触发
supportFragmentManager.commit {
add(R.id.contentLayout, FirstFragment())
addToBackStack(null)//点击返回键可以回到FirstFragment
}
//FirstFragment布局中有一个自定义MyButton且有bitmap属性
class MyButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
) : Button(
context, attrs, defStyle
) {
private val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.a)
}
然后触发加载SecondFragment;
//MainActivity触发
supportFragmentManager.commit {
replace(R.id.contentLayout, SecondFragment())
addToBackStack(null)
}
Android Profile可以发现有内存泄露
- MyButton中的bitmap无法释放。
为什么认为bitmap无法释放就是内存泄漏呢?
内存泄漏:简单点说,就是该释放的内存无法得到释放,而且内存不能被使用。 从Fragment的生命周期说起,从FirstFragment切换到SecondFragment,前者生命周期从onPause->onStop->onDestoryView,注意这里只走到onDestoryView,并没有onDetach以及onDestory。其实也很好理解,FirstFragment是加入了回退栈,后续是要被恢复,所以保留了Fragment对象,但为了不占用过多的内存,View会被销毁释放资源。 当FirstFragment从回退栈回到前台,会再次触发onCreateView重建View。既然View会重建,那么之前的View就是不需要的,留着也没用,就应该销毁掉。
该释放的View、Bitmap没有被释放,所以就出现了泄漏。
例子比较简单,只是为了说明问题,如果FirstFragment View持有大量占内存的对象,而且SecondFragment的加载需要耗费比较多的内存且存在跳转的其他页面的可能性,那么FirstFragment View的释放就显得很有必要。
补充引用链:FirstFragment-MyButton-Bitmap
onDestoryView官方注释
注意到这句“The next time the fragment needs * to be displayed, a new view will be created”,当Fragment恢复时,会创建新的view添加到Fragment,也就是重走onCreateView,那么我理解旧的view就应该可以被销毁。
/**
* Called when the view previously created by {@link #onCreateView} has
* been detached from the fragment. The next time the fragment needs
* to be displayed, a new view will be created. This is called
* after {@link #onStop()} and before {@link #onDestroy()}. It is called
* <em>regardless</em> of whether {@link #onCreateView} returned a
* non-null view. Internally it is called after the view's state has
* been saved but before it has been removed from its parent.
*/
@MainThread
@CallSuper
public void onDestroyView() {
mCalled = true;
}
LeakCanary日志
建议在onDestroyView要释放掉View
LeakCanary: Watching instance of androidx.constraintlayout.widget.ConstraintLayout (com.yang.myapplication.MyFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks)) with key 0f101dfe-5e4e-4448-95cc-f5d08bbdf06e
解决方案
将ViewBinding置空就欧了。其实这也是官方的建议,当你新建项目的时候,就能看到这样的案列。
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
总结
当出现Fragment没有被销毁(onDestory没有回调),而view需要被销毁时(onDestoryView),要注意把ViewBinding置空,以免出现内存泄露。
以上分析有不对的地方,请指出,互相学习,谢谢哦!
最后,如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。
小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!
不论遇到什么困难,都不应该成为我们放弃的理由!
很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,需要一份小编整理出来的学习资料的关注我主页或者点击扫描下方二维码免费领取~
这里是关于我自己的Android 学习,面试文档,视频收集大整理,有兴趣的伙伴们可以看看~
如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)