【问题标题】:Weak reference instead of getActivity() (Android avoid memory leak)?弱引用而不是 getActivity()(Android 避免内存泄漏)?
【发布时间】:2018-01-10 01:19:13
【问题描述】:

为了避免内存泄漏,我编写了以下方法,该方法将用于活动,主要用于片段(使用继承)。该方法应该允许我永远不会通过调用

直接引用活动
//this or getActivity()

方法是:

private WeakReference<BaseActivity> activityWeakReference = null; 

public BaseActivity getActivityFromWeakReference(){
        activityWeakReference = activityWeakReference == null ?
                new WeakReference<BaseActivity>((BaseActivity)getActivity()) :
                activityWeakReference;
        return activityWeakReference.get();
    }

根据内存泄漏威胁调用此方法getActivityFromWeakReference() 而不是getActivity() 是否安全?

如果这样做不安全,我是否应该返回 activityWeakReference 并改为调用其 get() 方法以确保安全?

我一直在多个片段中使用它,到目前为止我还没有遇到任何问题。我问这个问题是因为我读到了这个(here):

只要助手的生命周期在 Activity,则无需使用WeakReference。如果帮手 可以比Activity 寿命更长,那么你应该使用WeakReference 避免在系统运行时在对象图中保留Activity 摧毁它。

到目前为止,我还没有遇到过引用元素比活动更长寿的情况。如果您发现错误或可能的错误,请把它写在 cmets 中。

【问题讨论】:

  • 请注意,当activityWeakReference 不为空,但activityWeakReference.get() 为空时,您的方法可能返回空。
  • @Mateus Gondim,感谢您的输入,我在使用前已经检查了 null。

标签: java android memory-leaks weak-references


【解决方案1】:

这是完全可行的。例如你有这个伪代码:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

         new DownloadTask().execute();
    }

    public void showInfo() {
    }

    class DownloadTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            return null;
        }

        @Override
        protected void onPostExecute(Void data) {
            // we can call showInfo() activity because Asynctask hold an implicit reference to activity 
            showInfo();
        }
    }
}

在上面的代码中,有一种情况会导致内存泄漏。

解释如下:

当你创建DownloadTask 上面的例子时,java 调用DownloadTask 是一个inner class。内部类将隐式持有对外部类的引用,在本例中为MainActivity。此外,当您启动 asynctask 时,该 asynctask 将由系统持有直到它完成。例如,您下载需要 30 秒。在那 30 秒内,您旋转设备。当你旋转你的设备时,MainActivityre-created 并且通常旧的活动会被破坏。但在这种情况下,旧的活动不会被破坏,因为旧的MainActivity 实例由DownloadTask 持有,而DownloadTask 由系统持有。您将泄漏一个活动实例。

为了解决这个问题,您应该将上面的代码更改为:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new DownloadTask(this).execute();
    }

    public void showInfo() {
    }
}

class DownloadTask extends AsyncTask<Void, Void, Void> {
    WeakReference<MainActivity> mainActivityWeakReference;

    public DownloadTask(MainActivity activity) {
        mainActivityWeakReference = new WeakReference<MainActivity>(activity);
    }

    @Override
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void data) {
        if (mainActivityWeakReference.get() != null) {
            mainActivityWeakReference.get().showInfo();
        }
    }
}

在这种情况下,当新的MainActivity被创建时,旧的没有被DownloadTask持有(由于弱引用属性),所以旧的将来会被Android垃圾收集器销毁。您还应该在每次使用弱引用对象时进行检查,因为您不知道 GC 何时会销毁这些对象。

这是我自己的关于内存泄漏的另一种情况的博客。 Memory leak when using static inner class

希望对您有所帮助。

【讨论】:

  • 我应该明白,如果你使用我上面的方法(getActivityFromWeakReference()),你刚才描述的情况就可以了。
  • @MaximeClaude 是的,基本上这是真的。您将活动的 WeakReference 保留在“某个地方”,并且您应该将其作为您的方法(因为在某些情况下,它将为空,因为 GC 已清理它)。 “某个地方”取决于很多情况,我的例子只是其中之一。
  • 谢谢 :) 我会看看你的博客。
【解决方案2】:

在某些情况下,如果你的fragment设置为retain instance,它会比activity更长,或者你的fragment被泄露了。

【讨论】:

    猜你喜欢
    • 2017-01-23
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多