Android 开发过程中应该怎样防止内存泄漏

Android 开发过程中该怎样防止内存泄漏

关于内存泄漏和内存溢出的优化方式已经有很多,也有很多关于内存泄漏检测工具如 LeakCanary ,但这是在 App 发布或调试之后运行到某处时才能检测出。那么实际上,我们在编码过程当中也可以规范自己的编码方式,在可能发生内存方面问题的时候多细心一点。下面就来简单介绍下。

常见的内存泄露产生条件与解决方法

在 Android 程序开发中,当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,内存泄漏就产生了。

1、注意使用 Context

在某些时候,需要在工具类或单例模式类里,传入 context 作为类的成员变量,这样,在静态特征下的方法或单例持有的 context 对象的生命周期边长,如果该 context 已经在外部关闭了,那么该方法或单例将依然对 context 持有引用,因此造成泄露。

  • 可以传入 Application 的 context ,如 this.context = context.getApplicationContext();
  • 可以传入 Activity 的 context ,如 activity
2、注意非静态内部类,被创建成了静态实例

非静态匿名内部类会持有其外部类的隐式引用,如果该内部类在 Activity 中被创建了静态引用,将造成该 Activity 被持续保留,其下的各种 View、资源文件同样被应用,将造成大量内存泄漏。

  • 将该内部类设计为静态类
  • 将该内部类作为单例模式来引用和创建
3、注意子线程、handler 使用

早期的时候,处理耗时操作基本采用 Thread+Handler 的方式,后来逐步被 AsyncTask 取代,然后再是采用 RxJava 的方式,如今都推荐使用线程池来处理异步逻辑。
当某个耗时操作处于 Activity 或者前台活动中时,启动了异步线程,这是个比较耗时的操作,还没处理结束前台活动就退出了,但是异步线程中若还是有前台活动的引用就将出现内存泄漏。

  • 在前台活动销毁时,应当及时关闭或取消子线程,终止其继续运行
  • 在更新 UI 过程中,需做某些资源的判空处理
  • 使用 Handler 时可以对其持有的前台活动进行弱引用
4、注意资源对象是否及时关闭

资源对象在 Android 中都有缓冲,未及时关闭也将造成泄漏,即使是置空。

  • File 操作时,一些使用过的 Buffer、Stream 是否及时关闭
  • 数据库操作时,Cursor、数据库等是否及时关闭
  • 自定义 View 中引入 attr 自定义标签时 TypedArray 是否及时回收
  • Bitmap 操作后不使用时,是否调用其 recycle 方法回收
  • 另外,一些其它的资源文件可将其置空后调用 System.gc()
5、注意 WebView 使用

WebView 在解析网页时会申请 Native 堆内存用来保存页面的元素,当页面较复杂时或者包含图片时,会有很大的内存被占用。页面之间切换也会对之前的页面进行缓存,浏览十几个网页,会占用几百兆的内存。这样加载网页较多时,会导致系统不堪重负,最终强制关闭应用,也就是出现应用闪退或重启。即使 Activity 关闭时在 onDestroy 中调用如下代码也是没有任何作用的。

webView.pauseTimers();
webView.removeAllViews();
webView.destroy();
  • 不在布局文件中声明 WebView,在代码中通过 Application context 实例化,并 addView 方式添加
  • 使用第三方封装好的 WebView 框架
6、注意滚动视图、控件的使用

滚动试图或控件在 Android 有限屏幕内只展示一部分,应该注意不可见部分视图的缓存与回收,因为不可见部分可能同样占有了大量内存。

  • 使用 NestedScrollView 替代 ScrollView
  • 使用 RecyclerView 替代 ListView
  • 及时隐藏或置空不可见控件、避免过度绘制
7、注意广播、监听器、事件总线等的使用

有时在使用广播或监听器时,调用 registerReceiver() 后未调用 unregisterReceiver() 或在使用 EventBus 等时也需注册监听,此时应该在资源不使用或活动销毁时及时反注册。

你可能感兴趣的:(Android,开发)