setListener时内存泄漏

时间:2012-12-15 05:28:57

标签: java android

以下示例中的内存泄漏。

1.SpeedHelper.java:

public class SpeedHelper {

    interface Listener {
        void OnSelected(String entry);
    }
    static Listener sListener;

    static void setListener(Listener listener) {
        sListener = listener;
    }
    static Listener getListener() {
        return sListener;
    }
    static void clearListener() {
        sListener = null;
    }
}

2.CallSpeed.java

public class CallSpeed {

    protected void speed() {
        SpeedHelper.Listener litener = SpeedHelper.getListener();
        if (litener != null) {
            litener.OnSelected("mEntry");
        }
    }
}

3.MainActivity.java

public class MainActivity extends Activity {

    private CallSpeed callspeed;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SpeedHelper.setListener(mCallSpeedListener);
        callspeed = new CallSpeed();
        callspeed.speed();
    }
    private SpeedHelper.Listener mCallSpeedListener = new SpeedHelper.Listener() {

        @Override
        public void OnSelected(String entry) {
            Toast.makeText(getApplicationContext(), entry, Toast.LENGTH_SHORT).show();
        }
    };
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        SpeedHelper.clearListener();
    }
}

如何避免“sListener”的内存泄漏?

2 个答案:

答案 0 :(得分:1)

您可以尝试在static WeakReferences<Listener> sListener类中使用SpeedHelper进行变量定义,并将getter和setter方法更改为:

static void setListener(Listener listener) {
    sListener = new WeakReference(listener);
}
static Listener getListener() {
    return sListener.get();
}

答案 1 :(得分:1)

您的问题在于以下与静态字段sListener相关联的非静态封闭匿名类:

private SpeedHelper.Listener mCallSpeedListener = new SpeedHelper.Listener() {

        @Override
        public void OnSelected(String entry) {
            Toast.makeText(getApplicationContext(), entry, Toast.LENGTH_SHORT).show();
        }
    };

因为这是一个非静态的封闭类,所以它包含对其外部类MainActivity的引用。此隐藏引用阻止GC释放MainActivity类,因为包含隐藏引用的对象mCallSpeedListener将使用指令{{1}存储在静态字段sListener中}。因此,永远不会收集SpeedHelper.setListener(mCallSpeedListener);对象,永远不会调用其MainActivity函数,并且所有内容都保留在内存中; GC不可及。使用静态字段是对内存泄漏敞开的大门,封闭类中存在隐藏引用(匿名或非匿名)会放大此问题。

在您的情况下,您必须删除静态字段onDestroy或将匿名类更改为普通类;一个没有对其外sListener类的隐藏引用,或者在活动终止时在活动的另一个回调中直接调用MainActivity