可以在辅助类中使用上下文导致android中的内存泄漏

时间:2017-08-16 09:58:53

标签: android memory-management memory-leaks

可以在helper类中使用context导致android中的内存泄漏

我有一个带有以下方法的辅助类

public class HelperClass {
        private Context context;

        public HelperClass(Context context) {
            this.context = context;
        }
       public void Addfiles(Context context, String Filename) {
            try {
                Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                File f = new File(Filename);
                Uri contentUri = Uri.fromFile(f);
                mediaScanIntent.setData(contentUri);
                context.sendBroadcast(mediaScanIntent);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } 
    }

在我的MainActivity中,我想像这样称呼它

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        HelperClass h = new HelperClass(this);
        h.Addfiles(this,Filename);
    }
}

我想知道可以使用像这样的上下文导致内存泄漏,如果是这样,如何处理它。

1 个答案:

答案 0 :(得分:1)

TL; DR - 严格地说是上面的情况,不,因为在“onCreate”中MyActivity不会被销毁

答案很长:

通常,当垃圾收集器运行时,当某个对象无法进行垃圾回收时会发生内存泄漏,因为某些对象仍然引用它。 在您的情况下,刚刚创建活动,主要关注的是泄漏是否可能发生,因为HelperClass包含对它的引用。

首先,在正常情况下(除了AOS可能会杀死你的应用程序)MainActivity保证在调用onDestroy方法之前不会收集垃圾。这是因为在那之前(并且可能在那之后的一段时间 - 不相关)它将被Android框架本身引用。

另一方面,

HelperClassonCreate内的局部变量。完成onCreate后,HelperClass可能会在任何时候被垃圾收集,因为它没有引用它的任何对象(请参阅here)。因此HelperClass之前调用onDestroy的机会非常高。如果发生这种情况,则不会引用MainActivity - >没有泄漏。

如果在HelperClass上调用onDestroy之前不会对MainActivity进行垃圾回收,则事件仍然没有泄漏,因为垃圾收集器足够智能以便能够清理循环引用。

发生泄密需要发生的事情是,一个超过Activity的对象将保留对它的引用或其上下文。

假设你的代码是这样的:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final HelperClass h = new HelperClass(this);

    //does some work on a background thread, gets notified at some 
    //point in the future, through the callback, when the work 
    //has completed     
    longLivedComponent.doSomeBackgroundWork(new OnWorkFinishedListener(){

        @Override
        public void onWorkFinished(){
            h.Addfiles(this, filename);
        }

    });
}

现在,让我们假设以下事件序列:

  1. 用户打开应用,MainActivity#1已创建,其onCreate被称为
  2. 调用
  3. doSomeBackgroundWork,开始后台工作。当后台工作完成后,你的助手(引用MainActivity#1)将不得不做一些工作。
  4. 用户旋转设备,发生方向更改。
  5. MainActivity由Android重新创建。 MainActivity#1已被销毁(即onDestroy将被调用),并且将创建新的MainActivity#2
  6. MainActivity#2将发生第1,2步,即doSomeBackgroundWork#2将再次调用MainActivity。 (严格来说,这一步并不是真正相关,但仍然如此)
  7. 垃圾收集器运行。
  8. MainActivity#1在步骤#2 开始的后台工作完成。
  9. 通常,在步骤#6 时,MainActivity#1占用的内存将被释放,因为MainActivity#1已被销毁。

    但是,在此处描述的情况下,OnWorkFinishedListener需要longLivedComponent保留,直到后台工作完成。监听器既可以引用MainActivity#1(对其父类的隐式匿名内部类引用),也可以引用HelperClass实例,该实例还包含MainActivity#1的实例

    当垃圾收集器在步骤#6 看到此情况时,它会认为MainActivity#1仍处于活动状态&因为stil是指向它的对象。因此,它不会回收它的内存,你最终会在内存中出现MainActivity的两个实例并发生泄漏。

    为了防止这种情况,你可以:

    • 在长期对象将使用的类中使用应用程序上下文而不是活动上下文。此外,在您的情况下,您不需要任何特定于活动本身的内容
    • 确保任何长期存在的对象(在我们的例子中为longLivedComponent)或活动之间共享的对象在{{1}之后不会存储对Activity或其Context的引用已经被称为onDestroy()

    希望这有帮助