为了避免内存泄漏,我编写了以下方法,该方法将在 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):



到目前为止,我还没有遇到过这样的情况:所引用的元素比 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。此外,当您启动asynctask时,该asynctask将由系统保留直到完成。例如,下载需要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不会保留旧的ojit_code(由于引用属性较弱),因此将来会被Android Garbage Collector销毁。您还应该在每次使用弱引用对象时进行检查,因为您不知道确切的时间GC将销毁那些对象。

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

希望对您有所帮助。

09-10 12:30
查看更多