引用弱而不是getActivity()(Android避免内存泄漏)? [英] Weak reference instead of getActivity() (Android avoid memory leak)?

查看:230
本文介绍了引用弱而不是getActivity()(Android避免内存泄漏)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了避免内存泄漏,我编写了以下方法,该方法将在活动中使用,并且主要在片段中使用继承(使用继承).该方法应该允许我永远不要直接通过调用

To avoid a memory leak I wrote the following method that will be used in activities and mainly in fragments (using inheritance). That method is supposed to allow me to never directly refer to the activity by calling

//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()是安全的吗?

Is calling this method getActivityFromWeakReference() instead of getActivity() safe according to memory leak threat?

如果这样做不安全,我应该返回activityWeakReference并调用其get()方法以使其安全吗?

If it is not safe to do so, should I return the activityWeakReference and call its get() method instead, to make it safe?

我已经在多个片段中使用它,到目前为止我还没有遇到任何问题.我问这个问题是因为我读过此书(在这里):

I have been using it in multiple fragments and I haven't had any problem so far. I ask the question because I read this (here):

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

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.

到目前为止,我还没有遇到过这样的情况:所引用的元素比活动的寿命更长.如果发现错误或可能的错误,请在注释中写上.

So far, I haven't faced a case where a referred element outlived the activity. Please guys if you find an error or a possible one just write it in the comments.

推荐答案

这是完全可行的.例如,您具有以下伪代码:

It is totally feasible. For example you have this pseudocode code:

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();
        }
    }
}

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

On above code, there is a situation will caused memory leak.

以下是说明:

当您按照上述示例创建DownloadTask时,java调用DownloadTask内部类.内部类将隐式保存对外部类的引用,在这种情况下为MainActivity.而且,当您启动asynctask时,该asynctask将由系统保留,直到完成为止.例如,下载需要30秒.在这30秒钟内,您旋转设备.旋转设备时,MainActivity重新创建的并且经常会破坏旧的活动.但是在这种情况下,旧的活动不会被破坏,因为旧的MainActivity实例由DownloadTask保留,而DownloadTask由系统保留.您将泄漏一个活动实例.

When you create DownloadTask as above example, java call DownloadTask is an inner class. An inner class will implicit holds a reference to outer class, in this case is MainActivity. Moreover, when you start an asynctask, that asynctask will be held by system until it finish. For example, you download takes 30 seconds. In that 30 seconds, you rotate your device. When you rotate your device, MainActivity is re-created and often old activity will be destroyed. But in this case old activity isn't destroyed because the old MainActivity instance is held by DownloadTask and DownloadTask is hold by system. You will leak one activity instance.

要解决此问题,您应将上述代码更改为:

For fixing this, you should change above code to:

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 Garbage Collector销毁.您还应该每次使用弱引用对象时都要进行检查,因为您不知道确切的时间GC将销毁那些对象.

In this case, when new MainActivity is created, the old one isn't held by DownloadTask (due to weak reference attribute), so the old one will be destroyed by Android Garbage Collector in future. You also should to check every time you use a weak reference object, because you don't know exactly when GC will destroyed those object.

这是我自己的博客,涉及内存泄漏的另一种情况. 使用静态内部类时的内存泄漏

Here is my own blog about another situation of memory leak. Memory leak when using static inner class

希望获得帮助.

这篇关于引用弱而不是getActivity()(Android避免内存泄漏)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆