我们在JavaFX编程中,经常会将invalidation listener注册到Observerable接口的继承类的实例中,这是一种强引用“strong reference”,在生命周期短的程序中,这种问题引起的内存泄漏可惜忽略不计,因为当程序关闭后,泄露的内存都会释放掉。但是在生命周期长的程序中,这种注册方式会使得被观察实例始终会向注册的listener发送消息,即使这些listener再也不会使用。如下例,没有注销listener。
public class StrongListener {
public static IntegerProperty counter = new SimpleIntegerProperty(100);
public static void main(String[] args) {
// Add a change listener to the property
addStrongListener();
// Change counter value. It will fire a change event.
counter.set(300);
}
public static void addStrongListener() {
ChangeListener<Number> listener = StrongListener::changed;
counter.addListener(listener);
// Change the counter value
counter.set(200);
}
public static void changed(ObservableValue<? extends Number> prop,
Number oldValue,
Number newValue) {
System.out.print("Counter changed: ");
System.out.println("old = " + oldValue + ", new = " + newValue);
}
}
我们有以下几种方式来注销listener:
一:使用“void removeListener(InvalidationListener listener)”注销listener,具体实例如下:
public class CleanupListener {
public static void main(String[] args) {
// Add a change listener to the property
ChangeListener<Number> listener = CleanupListener::changed;
counter.addListener(listener);
// Change the counter value
counter.set(200);
// Remove the listener from property
counter.removeListener(listener);
// Will not fire change event as change listener has
// already been removed.
counter.set(300);
}
public static void changed(ObservableValue<? extends Number> prop,
Number oldValue,
Number newValue) {
System.out.print("Counter changed: ");
System.out.println("old = " + oldValue + ", new = " + newValue);
}
public static IntegerProperty counter = new SimpleIntegerProperty(100);
}
上例中,我们使用方法,将注册的listener移除,避免了内存泄漏。
如果我们在一个方法中将listener注册到Observerable中,但是没有地方适合写“removeListener方法”,那该如何避免内存泄漏呢?我们可以通过注册weak listener来手动注销。注意weak listener有“ WeakChangeListener”和“WeakInvalidationListener”两个,分别对应change、invalidation事件。具体使用方式如下:
ChangeListener<Number> cListener = create a change listener...
WeakChangeListener<Number> wListener = new WeakChangeListener(cListener);
将listener注册到weak listener,然后将weak listener注册到Observable中。
public class WeakListener {
public static void main(String[] args) {
// Add a weak change listener to the property
addWeakListener();
// It will fire a change event
counter.set(300);
// Try garbage collection
System.gc();
// Check if change listener got garbage collected
System.out.println("Garbage collected: " +
weakListener.wasGarbageCollected());
// It will fire a change event
counter.set(400);
// You do not need a strong reference of the change listener
changeListener = null;
// Try garbage collection
System.gc();
// Check if the change listener got garbage collected
System.out.println("Garbage collected: " +
weakListener.wasGarbageCollected());
// It will not fire a change event, if it was garbage collected
counter.set(500);
}
/**
@class WeakListener
@date 2020/5/3
@author qiaowei
@version 1.0
@brief Property adds weak listener wrapping change listener
@param
@return
@throws
*/
public static void addWeakListener() {
// Keep a strong reference to the change listener
changeListener = WeakListener::changed;
// Wrap the change listener inside a weak change listener
weakListener = new WeakChangeListener<>(changeListener);
// Add weak change listener
counter.addListener(weakListener);
// counter.addListener(changeListener);
// Change the value
counter.set(200);
}
public static void changed(ObservableValue<? extends Number> prop,
Number oldValue,
Number newValue) {
System.out.print("Counter changed: ");
System.out.println("old = " + oldValue + ", new = " + newValue);
}
public static IntegerProperty counter = new SimpleIntegerProperty(100);
public static WeakChangeListener<Number> weakListener;
public static ChangeListener<Number> changeListener;
}
运行结果:
Counter changed: old = 100, new = 200
Counter changed: old = 200, new = 300
Garbage collected: false
Counter changed: old = 300, new = 400
Garbage collected: false
Counter changed: old = 400, new = 500
来源:oschina
链接:https://my.oschina.net/weiweiqiao/blog/4263595