make sure to release all strong referenced to the I/O chart when closing the window

This commit is contained in:
Sebastian Stenzel
2020-06-16 15:35:12 +02:00
parent 1846c5c14c
commit d00d9d98dc
4 changed files with 67 additions and 21 deletions

View File

@@ -1,7 +1,9 @@
package org.cryptomator.ui.common;
import javafx.beans.binding.LongBinding;
import javafx.beans.binding.StringBinding;
import javafx.beans.value.ObservableObjectValue;
import javafx.beans.value.ObservableValue;
/**
@@ -29,4 +31,23 @@ public final class WeakBindings {
};
}
/**
* Create a new LongBinding that listens to changes from the given observable without being strongly referenced by it.
*
* @param observable The observable
* @return a LongBinding weakly referenced from the given observable
*/
public static LongBinding bindLong(ObservableValue<Number> observable) {
return new LongBinding() {
{
bind(observable);
}
@Override
protected long computeValue() {
return observable.getValue().longValue();
}
};
}
}

View File

@@ -3,6 +3,7 @@ package org.cryptomator.ui.vaultstatistics;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.binding.LongBinding;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
@@ -12,7 +13,9 @@ import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultStats;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.WeakBindings;
import javax.inject.Inject;
@@ -22,31 +25,38 @@ public class VaultStatisticsController implements FxController {
private static final int IO_SAMPLING_STEPS = 100;
private static final double IO_SAMPLING_INTERVAL = 0.5;
private final Stage window;
private final Vault vault;
@FXML
private LineChart<Number, Number> lineGraph;
private final VaultStats stats;
private final Series<Number, Number> readData;
private final Series<Number, Number> writeData;
private Timeline ioAnimation;
private final Timeline ioAnimation;
private final LongBinding bpsRead;
private final LongBinding bpsWritten;
public LineChart<Number, Number> lineGraph;
@Inject
public VaultStatisticsController(@VaultStatisticsWindow Stage window, @VaultStatisticsWindow Vault vault) {
this.window = window;
this.vault = vault;
this.stats = vault.getStats();
this.bpsRead = WeakBindings.bindLong(stats.bytesPerSecondReadProperty());
this.bpsWritten = WeakBindings.bindLong(stats.bytesPerSecondWrittenProperty());
readData = new Series<>();
this.readData = new Series<>();
readData.setName("Read Data"); // For Legend
//TODO Add Name to strings.properties
writeData = new Series<>();
this.writeData = new Series<>();
writeData.setName("Write Data");
//TODO Add Name to strings.properties
ioAnimation = new Timeline(); //TODO Research better timer
this.ioAnimation = new Timeline(); //TODO Research better timer
ioAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(IO_SAMPLING_INTERVAL), new IoSamplingAnimationHandler(readData, writeData)));
ioAnimation.setCycleCount(Animation.INDEFINITE);
ioAnimation.play();
// make sure to stop animating,
// otherwise a global timer (GC root) will keep a strong reference to animation
window.setOnHiding(evt -> {
ioAnimation.stop();
});
}
@FXML
@@ -84,20 +94,30 @@ public class VaultStatisticsController implements FxController {
}
// add latest value:
final long decBytes = vault.getStats().bytesPerSecondReadProperty().get();
final long decBytes = stats.bytesPerSecondReadProperty().get();
final double decMb = decBytes * BYTES_TO_MEGABYTES_FACTOR;
final long encBytes = vault.getStats().bytesPerSecondWrittenProperty().get();
final long encBytes = stats.bytesPerSecondWrittenProperty().get();
final double encMb = encBytes * BYTES_TO_MEGABYTES_FACTOR;
decryptedBytesRead.getData().get(IO_SAMPLING_STEPS - 1).setYValue(decMb);
encryptedBytesWrite.getData().get(IO_SAMPLING_STEPS - 1).setYValue(encMb);
}
}
public Vault getVault() {
return vault;
/* Getter/Setter */
public LongBinding bpsReadProperty() {
return bpsRead;
}
public long getBpsRead() {
return bpsRead.get();
}
public LongBinding bpsWrittenProperty() {
return bpsWritten;
}
public long getBpsWritten() {
return bpsWritten.get();
}
/*
public ReadOnlyObjectProperty<Vault> vaultProperty() {
return vault;
}*/
}

View File

@@ -19,6 +19,7 @@ import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import javax.inject.Provider;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.ResourceBundle;
@@ -39,11 +40,15 @@ abstract class VaultStatisticsModule {
Stage stage = factory.create();
stage.setTitle(String.format(resourceBundle.getString("vaultstatistics.title"), vault.getDisplayableName()));
stage.setResizable(false);
var weakStage = new WeakReference<>(stage);
vault.stateProperty().addListener(new ChangeListener<>() {
@Override
public void changed(ObservableValue<? extends VaultState> observable, VaultState oldValue, VaultState newValue) {
if (newValue != VaultState.UNLOCKED) {
stage.hide();
Stage stage = weakStage.get();
if (stage != null) {
stage.hide();
}
observable.removeListener(this);
}
}

View File

@@ -16,12 +16,12 @@
<HBox alignment="CENTER_RIGHT" spacing="6">
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondRead"/>
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondRead}"/>
mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.bpsRead}"/>
</HBox>
<HBox alignment="CENTER_RIGHT" spacing="6">
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondWritten"/>
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps"
mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondWritten}"/>
mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.bpsWritten}"/>
</HBox>
<LineChart