前言
在https://www.cnblogs.com/guanxinjing/p/10701192.html 这篇博客里了解了如何抓取与分析Android的内存泄露后,在这个博客里.将记录举例会引起内存泄露的情况.在android平台一般情况下的内存泄露都指页面(Activity或者Fragment等等). 因为他们会经常的进行创建与销毁. 所以除非特别指出,否则这篇博客的举例都是指view层泄露
单例持有
单例类
object Singleton{ private var mActivity :Activity? = null public fun setActivity(activity :Activity){ mActivity = activity; } }
这里不限于Activity,如果将fragment或者dialog 交给单例类持有,也将有相同的内存泄露情况
activity代码
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_test_demo) Singleton.setActivity(this) }
抓取内存泄露
解决思路
尽量不要将Activity交给单例持有,如果非要交给单例持有,也应该是弱引用持有.代码如下:
WeakReference弱引用
object Singleton{ private var mActivity : WeakReference<Activity>? = null public fun setActivity(activity :Activity){ mActivity = WeakReference(activity) } }
属性动画ObjectAnimator
泄露代码
override fun onStart() { super.onStart() startAnim() } private fun startAnim(){ val objectAnimatorA: ObjectAnimator = ObjectAnimator.ofFloat(textView2, "translationX", 100f, -100f, 0f) objectAnimatorA.setRepeatCount(-1) //持续时间 objectAnimatorA.duration = 3000 objectAnimatorA.start() }
解决思路
在activity onStop去执行cancel动画
线程或者Handler
在启用线程或者启用Handler在Activity里执行循环工作时导致的内存泄露. 另外Timer和TimerTask导致的内存泄露也是此类型的内存泄露这里不做重复举例
泄露代码
public lateinit var mHandler: Handler override fun onStart() { super.onStart() handler() } private fun handler(){ if (!::mHandler.isInitialized){ mHandler = Handler(Looper.getMainLooper()) } mHandler.postDelayed(Runnable { handler() }, 200) }
抓取内存泄露
解决思路
下面是Handler的解决,如果你是线程循环,建议使用AtomicBoolean 原子布尔来打断循环
public var mHandler: Handler? = null override fun onStart() { super.onStart() mHandler = Handler(Looper.getMainLooper()) handler() } override fun onStop() { super.onStop() //退出的时候将handler消息清空 mHandler?.removeCallbacksAndMessages(null) //并且一定要设置为null,否则removeCallbacksAndMessages 有概率不能清除已经正在执行的代码,导致重新循环 mHandler = null } private fun handler(){ if (mHandler == null){ //此处一定要增加判空 return } mHandler?.postDelayed(Runnable { handler() }, 200) }
传入接口泄露
泄露代码
单例代码
object Singleton{ public var mListener: OnListener? = null public fun setActivity(listener :OnListener){ mListener = listener } } interface OnListener{ fun onData() }
activity代码
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_test_demo) Singleton.setActivity(object : OnListener { override fun onData() { } }) }
抓取内存泄露
解决思路
请确保在每一个在activity匿名注册的接口在,activity需要被销毁的时候设置为null
非静态内部类
泄露代码
/** * =============================================================== * 第一种情况 * =============================================================== */ public class TestActivity extends AppCompatActivity { private static DemoBean mDemoBean; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); //当前外部类静态持有 mDemoBean = new DemoBean(); } /** * 未添加static静态修饰 */ public class DemoBean{ private String name = ""; private int age = 1; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } } /** * =============================================================== * 第二种情况 * =============================================================== */ public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); //交给单例持有 Singleton.INSTANCE.setDemoBean(new DemoBean()); } /** * 未添加static静态修饰 */ public class DemoBean{ private String name = ""; private int age = 1; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } }
抓取内存泄露
问题原因
创建内部类的时候未添加static修饰, 并且将实例的内部类传给单例或者其他类保管. 非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。
解决思路
在创建任何内部类的时候养成随手添加static,并且思考接下来的业务是否需要取消static. 如非必要不创建非静态的内部类
注册LiveData或者MutableLiveData的观察者导致的内存泄露问题
这个内存泄露不是指Activity或者Fragment内存泄露了, 而是注册的Observer重复多次创建,这个Observer内存泄露了
问题描述
当你在一些主页Activity里注册LiveData的观察者时,有可能是在onStart或者onResume生命周期里注册它。这个时候就有可能导致内存泄露。
抓取内存泄露
问题原因
其实在正常情况下onStart或者onResume生命周期里注册观察者Observer也没问题。但是如果你的主页如果是不需要退出,就不会走onDestroy生命周期(特别是在一些Android物联设备上,本身主页就是桌面,且无法退出)。这个时候就会出现在其他Activity返回后在onStart或者onResume生命周期里反复注册观察者Observer。
现在抓取内存泄露时候可以看到多个内部类(就是Observer类)不会被移除。这是因为LiveData的观察者在Activity或者Fragment里不需要手动去注销,但是也是需要在onDestroy执行时候才会注销的。
解决思路
请将它放到onCreate生命周期里注册Observer,防止反复注册。
Dialog对话框泄漏
问题描述

End
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/15832595.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库