Android开发 如何最优的在 Activity 里释放资源

栏目: IT技术 · 发布时间: 4年前

内容简介:作者:禄子_c79b链接:https://www.jianshu.com/p/b1e7422053a5

code小生 一个专注大前端领域的技术平台 公众号回复 Android 加入安卓技术群

作者:禄子_c79b

链接:https://www.jianshu.com/p/b1e7422053a5

声明:本文已获 禄子_c79b 授权发表,转发等请联系原作者授权

前言

当前你已经入门Android开发,开始关注深入的问题,你就会碰到一个Android开发阶段经常碰到的问题,那就是内存泄漏. 其实大多数Android的内存泄漏都是因为activity里的资源释放不正确导致,activity与单例或者接口互相持有无法释放.这篇博客就来讲解如何在Android里最优的释放资源.

错误释放资源的一些例子

在看正面例子之前,我们看看反面例子,了解为什么经常莫名其妙的内存泄露

  • 在Activity的onDestroy()的生命周期里释放资源

在下面的onDestroy()方法里我们有一个叫mHttpList的资源要释放,我们都知道activity的生命周期的最后是onDestroy方法,那么为什么在onDestroy()里释放资源会有问题呢?

问题出在onDestroy()生命周期并不是立即执行的.Activity退出前台后先是进入栈里的.是否执行onDestroy()是交给系统决定的,一般情况下系统的确会及时的运行onDestroy()方法销毁activity,但是在一些Activity跳转频繁的情况下可能系统并不会马上运行onDestroy()方法.这个时候问题就出现了你认为应该结束的资源并没有马上结束可能导致一些回调报错或者内存泄露.

@Override
protected void onDestroy() {
  super.onDestroy();
  if (mHttpList != null){
    mHttpList.release();
    mHttpList = null;
  }

}
  • 在Activity的finish()方法里释放资源

同上环境,那么finish方法里释放资源有那些问题呢?

重写的finish()是一个释放资源的好地方,在按返回键(或者你自己主动调用onBackPressed()方法)和主动调用finish()方法时,重写的finish()都是会运行的.但是在这个方法在有一种情况下是不运行的,就是在后台太久后的自动清理或者其他Activity的启动模式是android:launchMode="singleTask" 在其他activity的singleTask下会自动清理它栈前的所以Activity,在这种情况下如果你的activity要被清理掉finish()方法是不会运行的.这样你的资源就没有被释放了.

@Override
public void finish() {
  super.finish();
  if (mHttpList != null){
    mHttpList.release();
    mHttpList = null;
  }
}
  • 在Activity的onPause()和onStop()里释放资源

在onPause()和onStop()我们都知道activity后台的时候会调用这2个生命周期先onPause() 然后在 onStop(),如果是Dialog模式的Activity弹出只会进入onPause(). 他们的问题是什么呢?

问题是如果在操作太快的操作前后台,就会导致我们的资源需要频繁的在onRestart()或者onResume() 重新初始化或者注册.这是较好的一种释放资源的方式一般情况下是推荐这种的,但是快速频繁的操作初始化与释放是最容易出现内存泄漏的...特别是初始化如果是耗时的...

@Override
protected void onPause() {
  super.onPause();
  Log.e(TAG, "onPause: ");
}

@Override
protected void onStop() {
    super.onStop();
    Log.e(TAG, "onStop: ");
}

推荐在Activity里释放资源的方式

onPause()或者onStop()结合onDestroy(),调用isFinishing()在方法判断后释放资源,如下代码:

private boolean mIsRelease = false;

/**
 * 释放资源
 */
private void release(){
    if (mIsRelease){
        return;
    }
    if (isFinishing()) {
        if (mHttpList != null) {
            mHttpList.release();
            mHttpList = null;
        }
    }
    mIsRelease = true;
}

@Override
protected void onPause() {
    super.onPause();
    release();
}

@Override
protected void onStop() {
    super.onStop();
    //结合实际情况也可以在onStop方法里 释放资源

}

@Override
protected void onDestroy() {
    super.onDestroy();
    release();
}

注意添加判空或者也可以在方法里套一个全局布尔值来判断是否释放过资源,防止重复释放资源... 这里为什么onDestroy()还要运行一次?下面会说明原因.

首先讲讲isFinishing()的作用就是判断这个activity是不是需要被销毁,还是只是进入后台.我验证过以下情况:

  1. 在主动调用finish()方法的情况下,isFinishing() 返回的是true

  2. 在主动调用onBackPressed()方法或者按返回键的情况下, isFinishing() 返回的是true

  3. 如果只是因为进入到其他Activity而退到后台, isFinishing() 返回的是false

但是,isFinishing()并不是完美的,还有一种情况可以跳过清理的,那就是SingleTask模式下这个Activity要被销毁,但是后台因为入栈(入深栈最少在第三层的那种情况)已经触发过onPause或者onStop,所以SingleTask的清理就跳过了isFinishing()判断,直接走到了onDestroy().

所以,我们需要在onDestroy()再次兜底,保证不会因为SingleTask的原因没有释放资源.

总结

以上这种释放资源的组合,目的是在Activity真的要被销毁的时候能尽快的释放资源,又可以防止Activity只是在后台时需要重复注册资源,最后依靠onDestroy()兜底保证资源不会因为SingleTask原因没有释放

在Fragment里的资源释放

它有也要一个类似的方法可以判断,是否是被移除Activity

final public boolean isRemoving() {
return mRemoving;
}

以上所述就是小编给大家介绍的《Android开发 如何最优的在 Activity 里释放资源》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Android编程权威指南

Android编程权威指南

[美] Bill Phillips、[美] Brian Hardy / 王明发 / 人民邮电出版社 / 2014-4 / CNY 99.00元

权威、全面、实用、易懂,是本书最大的特色。本书根据美国大名鼎鼎的Big Nerd Ranch训练营的Android培训讲义编写而成,已经为微软、谷歌、Facebook等行业巨头培养了众多专业人才。作者巧妙地把Android开发所需的庞杂知识、行业实践、编程规范等融入一本书中,通过精心编排的应用示例、循序渐进的内容组织,以及循循善诱的语言,深入地讲解了Android开发的方方面面。如果学完一章之后仍......一起来看看 《Android编程权威指南》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具