弱引用而不是getActivity()(Android避免内存泄漏)?

时间:2017-08-02 17:18:05

标签: java android memory-leaks weak-references

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

直接引用该活动
//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   摧毁它。

到目前为止,我还没有遇到一个被推荐的元素超过活动的情况。如果您发现错误或者可能的错误请大家在评论中写下来。

2 个答案:

答案 0 :(得分:9)

这完全可行。例如,您有这个伪代码:

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调用DownloadTaskinner 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不会被var selectChoices = document.querySelectorAll('#translateBoxCover .choices') 保留(由于弱引用属性),因此旧的将被Android垃圾收集器销毁未来。每次使用弱引用对象时也应检查,因为您不确切知道GC何时会破坏这些对象。

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

希望得到这个帮助。

答案 1 :(得分:0)

在某些情况下,如果您的片段设置为保留实例,它将比活动长,或者您的片段被泄露。