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

标签 java android memory-leaks weak-references

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

直接引用该 Activity
//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() 方法,以确保安全?

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

As long as the lifetime of the helper is within the lifetime of the Activity, then there's no need to use a WeakReference. If the helper can live longer than the Activity, then you should use a WeakReference to avoid retaining the Activity in your object graph when the system destroys it.

到目前为止,我还没有遇到过引用元素比 Activity 还长的情况。请大家,如果您发现错误或可能的错误,请将其写在评论中。

最佳答案

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

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。此外,当您启动一个异步任务时,该异步任务将由系统持有,直到它完成。比如你下载需要30秒。在那 30 秒内,您旋转设备。当您旋转设备时,MainActivityre-created并且经常会破坏旧的 Activity 。但在这种情况下,旧 Activity 不会被破坏,因为旧的 MainActivity 实例由 DownloadTask 持有,而 DownloadTask 由系统持有。您将泄漏一个 Activity 实例。

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

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

希望这对您有所帮助。

关于java - 弱引用而不是 getActivity()(Android 避免内存泄漏)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45467205/

相关文章:

java - 具有多个帖子资源的 ReSTLet 服务

java - 修改 SeaGlass JComponents

android - setContentView() 的类型是什么

java - Android - 每 15 分钟运行一次后台任务,即使应用程序没有运行

javascript - 如何调用可以读取条形码并将数据返回到html的 native 应用程序

linux - 比较 valgrind、massif、top 和 pmap

java - PagerAdapter 中的 ImageButton onclick。需要转到另一个类/XML 文件。错误

linux - Activemq内存消耗高

c - 试图理解c中NULL的内存泄漏

java - Domino JVM 内存和 POI