Mám Swing akcie trieda, ktorá funguje takto:
package org.trypticon.hex.gui.datatransfer;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorListener;
import java.awt.event.ActionEvent;
import javax.annotation.Nonnull;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.TransferHandler;
import org.trypticon.hex.gui.Resources;
import org.trypticon.hex.gui.util.FinalizeGuardian;
import org.trypticon.hex.gui.util.FocusedComponentAction;
public class PasteAction extends FocusedComponentAction {
private final FlavorListener listener = (event) -> {
// this method in the superclass calls back `shouldBeEnabled`
updateEnabled();
};
@SuppressWarnings({"UnusedDeclaration"})
private final Object finalizeGuardian = new FinalizeGuardian(() -> {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.removeFlavorListener(listener);
});
public PasteAction() {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.addFlavorListener(listener);
}
@Override
protected boolean shouldBeEnabled(@Nonnull JComponent focusOwner) {
TransferHandler transferHandler = focusOwner.getTransferHandler();
if (transferHandler == null) {
return false;
}
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
DataFlavor[] flavorsInClipboard = clipboard.getAvailableDataFlavors();
return transferHandler.canImport(focusOwner, flavorsInClipboard);
}
@Override
protected void doAction(@Nonnull JComponent focusOwner) throws Exception {
Action action = TransferHandler.getPasteAction();
action.actionPerformed(new ActionEvent(
focusOwner, ActionEvent.ACTION_PERFORMED, (String) action.getValue(Action.NAME)));
}
}
Na FinalizeGuardian
uvedené je tu v súčasnosti vykonáva podľa finalize()
:
package org.trypticon.hex.gui.util;
public final class FinalizeGuardian {
private final Runnable cleanupLogic;
public FinalizeGuardian(Runnable cleanupLogic) {
this.cleanupLogic = cleanupLogic;
}
@Override
protected final void finalize() throws Throwable {
try {
cleanupLogic.run();
} finally {
super.finalize();
}
}
}
Takže, z pochopiteľných dôvodov, chcela by som sa prepnúť na používanie Cleaner
za to.
Prvý pokus bol niečo ako toto:
package org.trypticon.hex.gui.util;
import java.lang.ref.Cleaner;
public final class FinalizeGuardian {
private static final Cleaner cleaner = Cleaner.create();
public FinalizeGuardian(Runnable cleanupLogic) {
cleaner.register(this, cleanupLogic);
}
}
Problém je, že teraz objektu nikdy sa stáva phantom dosiahnuteľné, pretože:
Cleaner
sám má silný odkaz nacleanupLogic
cleanupLogic
drží odkaz nalistener
s cieľom odstrániť poslucháčlistener
drží odkaz na akciu trieda aby sa hovorupdateEnabled
na to- akcie triedy drží odkaz na
FinalizeGuardian
tak, že to ani nemôže byť zbierané predčasne
Pretože FinalizeGuardian
sám nikdy sa stáva phantom dosiahnuteľný čistiaci prostriedok nikdy nebude tzv.
Takže to, čo by som chcel vedieť, je, existuje spôsob, ako reštrukturalizovať tento dodržiavať pravidlá potrebné na to, aby Cleaner
pracovať správne, že nebude zahŕňať lámanie zapuzdrenie pohybom poslucháč mimo môjho akcie trieda?