I have some complex Observable structures, which may or may not be bad ideas, but which are not the focus of this question.
The problem with those structures is that they generate a lot of invalidations of Observable objects being displayed by the UI. As near as I can tell, when the JavaFX UI is displaying something, it registers a ChangeListener on it, so any attempts to use lazy evaluation go out the window. That is, invalidating the observable seems to tell the UI that it has potentially changed, which causes the UI to immediately request it's value, forcing it to evaluate immediately.
So, I had the idea of deferring the invalidations via Platform.runLater().
I created a class called DeferredBinding that delegates everything to a wrapped Binding, except the invalidate() method, which it defers to the JavaFX UI thread to be processed later. It seems to work... I can invalidate a hundred times and it only seems to actually process the invalidation once.
But, I've not seen this pattern before and I am afraid it might fall into the category of "nice try but bad idea".
So, question: is this a bad idea? I am particularly concerned of errors introduced into other Observable objects that depend on the DeferredBinding. Will they be fine once the Platform.runLater() happens?
package com.myapp.SAM.model.datastructures;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.binding.Binding;
import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
/**
* Specialized binding that defers its invalidations to the JavaFX UI thread in a throttled manner. The idea being that, if invalidate() is called many times,
* it only basically happens once (when the UI thread gets to it).
*/
public class DeferredBinding<T> implements Binding<T> {
private static final Logger logger = Logger.getLogger(DeferredBinding.class.getName());
private final Binding<T> binding;
private final AtomicBoolean pendingInvalidation = new AtomicBoolean(false);
public DeferredBinding(Binding<T> binding) {
this.binding = binding;
}
#Override
public void addListener(ChangeListener<? super T> listener) {
binding.addListener(listener);
}
#Override
public void removeListener(ChangeListener<? super T> listener) {
binding.removeListener(listener);
}
#Override
public T getValue() {
return binding.getValue();
}
#Override
public void addListener(InvalidationListener listener) {
binding.addListener(listener);
}
#Override
public void removeListener(InvalidationListener listener) {
binding.removeListener(listener);
}
#Override
public boolean isValid() {
return binding.isValid();
}
/**
* Override logic for invalidate() method to defer invalidation to runLater. Throttle the invalidations so as not to floor the JavaFX UI thread with
* multiple calls
*/
#Override
public void invalidate() {
if (pendingInvalidation.getAndSet(true) == false) {
Platform.runLater(() -> {
// Signal that the UI is processing the pending invalidation, so any additional invalidations must schedule another update.
pendingInvalidation.set(false);
binding.invalidate();
});
}
}
#Override
public ObservableList<?> getDependencies() {
return binding.getDependencies();
}
#Override
public void dispose() {
binding.dispose();
}
}
I would not try to solve performance problems ahead of time. Measure your application to determine if you have a problem and then go ahead..
Let's assume you have a problem, there are many ways to solve your abstract problem. Three solutions come to my mind:
1
Coalesce updates (Platform.runLater()) to prevent saturation of the FX event queue as you have done in your example.
And since you are just invalidating the binding you do not have to fear loosing a value on the way. So it seems (without knowing the full application) that this way should work.
2
Using the Nodes built-in behavior of marking regions dirty for (re-)layouting. At some point you will call javafx.scene.Parent.requestLayout() (this is the "invalidation") which will at some point in the future call javafx.scene.Parent.layoutChildren() to apply the dirty attributes to the region.
3
Using solution 2 in a different way: By using a virtualized layout container. The TableView, TreeTableView and ListView all use the virtualized approach to update only the visible cells.
See com.sun.javafx.scene.control.skin.VirtualFlow and com.sun.javafx.scene.control.skin.VirtualContainerBase for some JDK examples, another example would be the Flowless API.
As you did not tell any specifics I can not guide you any further. But it should be clear, that your approach may very well work and there are other ways.
Related
I have a Swing action class which works as follows:
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)));
}
}
The FinalizeGuardian referred to here is currently implemented using 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();
}
}
}
So, for obvious reasons, I'd like to switch to using Cleaner for this.
The first try was something like this:
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);
}
}
The problem is that now the object never becomes phantom reachable, because:
Cleaner itself holds a strong reference to cleanupLogic
cleanupLogic holds a reference to listener in order to remove the listener
listener holds a reference to the action class in order to call updateEnabled on it
the action class holds a reference to the FinalizeGuardian so that it doesn't get collected prematurely
Because the FinalizeGuardian itself never becomes phantom reachable, the cleaner will never be called.
So what I'd like to know is, is there a way to restructure this to follow the rules required to make Cleaner work correctly that doesn't involve breaking encapsulation by moving the listener to outside my action class?
As long as the FlavorListener is registered at an event source, it will never become unreachable (as long as the event source is still reachable). This implies that the PasteAction instance which the listener updates will also never become unreachable, as the listener has a strong reference to it.
The only way to decouple their reachability is to change the listener, to only maintain a weak reference to the object it updates. Note that when you’re using a Cleaner instead of finalize(), the FinalizeGuardian is obsolete.
The code would look like
public class PasteAction extends FocusedComponentAction {
static FlavorListener createListener(WeakReference<PasteAction> r) {
return event -> {
PasteAction pa = r.get();
if(pa != null) pa.updateEnabled();
};
}
private static final Cleaner CLEANER = Cleaner.create();
static void prepareCleanup(
Object referent, Clipboard clipboard, FlavorListener listener) {
CLEANER.register(referent, () -> clipboard.removeFlavorListener(listener));
}
public PasteAction() {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
FlavorListener listener = createListener(new WeakReference<>(this));
clipboard.addFlavorListener(listener);
prepareCleanup(this, clipboard, listener);
}
…
Note that the critical parts have been placed into static methods, to make accidental capture of the this reference impossible. These methods get the minimum necessary to do their job, createListener only receives a weak reference to the action and prepareCleanup gets the referent as Object, as the cleaning action must not access any members of the action but receive the necessary values as separate parameters.
But after showing, how a cleaner use may look like, I have to strongly discourage from using this mechanism, especially as the only cleanup mechanism. Here, it is not only affecting memory consumption, but also the behavior of the program, because, as long as the references have not been cleared, the listener will keep getting informed and keep updating an obsolete object.
Since the garbage collector is only triggered by memory needs, it is perfectly possible that it doesn’t run or doesn’t care about these few objects, because there’s enough free memory, while the CPU is under heavy load, because of lots of obsolete listeners being busy to update obsolete objects (I’ve seen such scenarios in practice).
To make matters worse, with concurrent garbage collectors, it’s even possible that their collection cycle repeatedly overlaps with an actually obsolete execution of updateEnabled() triggered by the listener (because the reference was not cleared yet). Which will actively prevent the garbage collection of these objects, even when the garbage collector runs and would otherwise collect them.
In short, such cleanup should not rely on the garbage collector.
I have some questions regarding the Presenter’s start(), stop() method. What would you normally put into these methods to prevent memory leaks or any potential problem.
For example, I have an Activity that host a VideoView. The videoPath passed to the Activity will be passed to the Presenter to a VideoUtility to trim the original video into a shorter one before getting passed back to the Activity to be played with the VideoView.
Here’s the confusion: I don’t know where is the appropriate place to call the trimVideo() method as it essentially only need to happen once (unlike in the Android Architect Blueprint, the task is updated with latest data, and thus it’s put in the onResume()).
Please see the code snippet below:
VideoEditorContract:
public interface VideoEditorContract {
interface View extends BaseView<Presenter> {
void playTrimVideo(String trimmedVideoPath);
}
interface Presenter extends BasePresenter {
}
}
VideoEditorActivityBase:
public class VideoEditorActivityBase extends AppCompatActivity implements VideoEditorContract.View {
private VideoEditorContract.Presenter mPresenter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_editor);
String videoPath = getIntent().getStringExtra(RequestCode.EXTRA_VIDEO_PATH);
mPresenter = new VideoEditorPresenter(videoPath, this);
}
#Override
public void onResume(){
super.onResume();
mPresenter.start();
}
#Override
public void playTrimVideo(String trimmedVideoPath) {
final VideoView vv = findViewById(R.id.act_video_editor_videoView);
vv.setVideoPath(trimmedVideoPath);
vv.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
vv.start();
}
});
}
#Override
public void setPresenter(VideoEditorContract.Presenter presenter) {
//do nothing as this activity has already init a presenter
}
}
VideoEditorPresenter:
public class VideoEditorPresenter implements VideoEditorContract.Presenter {
private final VideoEditorContract.View mVideoEditorView;
#NonNull
private String mVideoPath;
public VideoEditorPresenter(#NonNull String videoPath, #NonNull VideoEditorContract.View videoEditorView) {
mVideoPath = checkNotNull(videoPath);
mVideoEditorView = checkNotNull(videoEditorView, "videoEditorView cannot be null!");
mVideoEditorView.setPresenter(this);
//trimVideo(); //should I do it here since this task is only need to be done once
}
#Override
public void start() {
//trimVideo(); //I can do it here but then I need to introduce a control variable; not sure if this is the best practice
}
private void trimVideo() {
//trim video stuff
}
// Currently it doesn't have a stop() method. But if it have one,
// what should I put in it? Releasing and clean up the
// VideoUtility I suppose?
}
I got the answer from Francesco Cervone in Medium about this matter (his article is also an excellent resource on MVP, btw. Very well in tune with the Android Architect Blueprint). I leave the relevant bit here for future reader.
Hi, thank you.
Well, I think that the video should be trimmed in the Presenter#start(). Then, after the video has been trimmed, the presenter should call view.playTrimmedVideo(). You shouldn’t do anything in the presenter constructor.
I suppose the video “editing” is something expensive, so you should do that in a separate thread (using for example an async task). You need to implement the Presenter#stop() method because you have to cancel ongoing operations if there are any, unless you retain the presenter.
You said that the trimVideo should be called just once. You could cache/persist in some way the result of trimVideo so that if the video has been already trimmed, you use it.
I hope I answered your question.
"Could you elaborate more on why shouldn’t we put anything in the Presenter’s constructor? I’ve seen the Presenter’s bare minimal constructor in a couple of places but I don’t understand the reason behind it."
First, it’s a responsibility problem: you are going to create an instance of Presenter, and I don’t think that the video editing is something that belongs to the construction of that object.
Second, you don’t know when the presenter is being instantiated, so you shouldn’t execute expensive tasks in the constructor. If you use some dependency injection framework, the construction of the Presenter would be managed by the framework itself and it needs to be efficient. The construction of other objects could depend on the presenter one.
I have a #RabbitListener and properly working consuming from queue.
In my listener I set context.
I know that there are many (configurable) threads consuming the same queue (so in real executing the same lisener code).
Now, I consdier when is good time to clear context ?
To be more precisely, it is problem for me to express:
"When you end consuming (no matter with exception or not) do clear context)"
Below, you can see a scheme of my problem:
public class CustomContextHolder {
private static final ThreadLocal<DatabaseType> contextHolder =
new ThreadLocal<DatabaseType>();
public static void setContext(DatabaseType databaseType) {
contextHolder.set(databaseType);
}
public static CustomerType getContext() {
return (CustomerType) contextHolder.get();
}
public static void clearContext() {
contextHolder.remove();
}
}
#RabbitListener
void listenMessage(Message message) {
...
CustomContextHolder.set(...);
}
It's generally better to use stateless objects as listeners rather than using ThreadLocal.
However, if you are forced to keep state this way, you can implement ApplicationListener<AmqpEvent>.
The ApplicationListener will receive several events; specifically, the AsyncConsumerStoppedEvent when the consumer is stopped normally and ListenerContainerConsumerFailedEvent if the consumer stops abnormally. These two events are published on the listener thread, so you can clear your ThreadLocal there.
Other events may or may not be published on the listener thread.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have never before seen such a thing, so let's say I have such listener object:
MyWhateverListener dafuqListener = new MyWhateverListener() {
#Override
public void onSuccessCall(String s) {
// success call
}
#Override
public void onFailCall(boolean b) {
// fail call
}
#Override
public boolean onDafuqCall(int i, boolean b) {
// some whatever code
return false;
}
};
Everything fine, the appropriate method will be called back to, when some action succeedes, but what's with this return inside onDafuqCall method, why is it needed, where it will return something?
P.S. This interface is from an Android ads provider's SDK.
This is really quite a normal thing. A listener/observer interface is paired with a subject/event throwing class. Often you want your listeners to be totally disconnected from the behaviour of the subject, to the extent that the subject neither knows nor cares about how many listeners are registered. This is the 'pure' pattern. And this is the most common and it makes sense for all the methods to be void, since they are called only by the subject and the subjects behaviour does not depend on its listeners.
However, sometimes it makes sense for a listener to have other methods not intended to be called by the subject, and for the listener to act as a bridge between the state of the subject and some other part of the program. One common example is making special listeners for debugging. Here you make a new listener which extends your previous listener but it also keeps track of exactly when it is called by a subject, it then has a method with a return value so that your testing code can access this state, and see exactly what that listener was doing.
Finally, it occasionally makes sense to have listeners which affect the behaviour of the subject. In this case return methods are necessary. But this is rare and not without danger, it is sometimes used e.g. to make sure that things are deleted in a chain in the right order. So you stop the chain of deletes if you failed to delete a child. It has a name, but I cannot remember exactly what this pattern is called right now.
It is quite unclear what you ask but I'll give it a shot.
Interfaces are a way to allow objects to follow a specific pattern. They come handy, for instance, when I have an interface called "Listener" and five implementations:
ActionListener, MouseListener, KeyListener, CloseListener, StateChangeListener.
If I want to have a method allowing the user to register a user, instead of having to make separate "registerListener" methods for each implementation I can have: registerListener(Listener l).
Now back to your post, Interfaces may contain methods with return values, as an example if I have an interface called Event, and it contains a method called isCanceled() that returns boolean, then if I have an implementation called "ClickEvent" and I want to check if this event (after it has been called) is canceled by anyone or anything I'll invoke the isCanceled() method and that should return a value, because it is handled by the implementing object.
So to wrap this up, the return value is needed by the piece of code that calls the listener to get information. If we look in Java interfaces and their implementations we can find a ton of examples. You can check for yourself by looking into the java.uti.List interface source and an implementation like java.util.ArrayList
More information can be obtained from the Docs:
https://docs.oracle.com/javase/tutorial/java/concepts/interface.html
https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html
EDIT #1: Here is the example explained above, represented in code:
The event interface:
package com.fillpant.examples;
public interface Event {
public boolean isCanceled();
public void setCanceled(boolean value);
}
The ClickEvent (that implements Event):
package com.fillpant.examples;
public class ClickEvent implements Event {
private boolean canceled = false;
#Override
public boolean isCanceled() {
return canceled;
}
#Override
public void setCanceled(boolean value) {
canceled = value;
}
}
The place where ClickEvent is called. Here I demonstrate why the return value is needed (See the isCanceled() method):
package com.fillpant.examples;
public class EventCaller {
//This class calls an event, and all the listeners will have to handle it;
public void callClickEvent(){
Event e = new ClickEvent();
for(Listener l : all_registered_listeners){//this is hypothetical, if we had listeners.
l.event(e);
}
if(e.isCanceled()) return;
else{
//DoStuff
}
}
}
If you have any question don't hesitate to ask :D
This is my understanding about the topic:
Generally Listener/call-back methods don't need to return anything and they are called in response to an event.
e.g. onClick() method of OnClickListener.
OnClickListener onClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
//some click handling code
}
};
But if they are part of an event-chain then a boolean return type is used to either abort of continue the execution of events. e.g. onDrag() method from OnDragListener.
OnDragListener onDragListener = new OnDragListener() {
#Override
public boolean onDrag(View v, DragEvent event) {
//some drag handling code
return false;
}
}
Documentation of this method says "return true if the drag event was handled successfully, or false if the drag event was not handled. Note that false will trigger the View to call its onDragEvent() handler."
so it is not very uncommon to have return in call-back/event-handling methods if they are part of chain of events. And what should be returned is part of the documentation of the API.
I just found an interesting situation. Suppose you have some SwingWorker (I've made this one vaguely reminiscent of my own):
public class AddressTreeBuildingWorker extends SwingWorker<Void, NodePair> {
private DefaultTreeModel model;
public AddressTreeBuildingWorker(DefaultTreeModel model) {
}
#Override
protected Void doInBackground() {
// Omitted; performs variable processing to build a tree of address nodes.
}
#Override
protected void process(List<NodePair> chunks) {
for (NodePair pair : chunks) {
// Actually the real thing inserts in order.
model.insertNodeInto(parent, child, parent.getChildCount());
}
}
private static class NodePair {
private final DefaultMutableTreeNode parent;
private final DefaultMutableTreeNode child;
private NodePair(DefaultMutableTreeNode parent, DefaultMutableTreeNode child) {
this.parent = parent;
this.child = child;
}
}
}
If the work done in the background is significant then things work well - process() is called with relatively small lists of objects and everything is happy.
Problem is, if the work done in the background is suddenly insignificant for whatever reason, process() receives a huge list of objects (I have seen 1,000,000, for instance) and by the time you process each object, you have spent 20 seconds on the Event Dispatch Thread, exactly what SwingWorker was designed to avoid.
In case it isn't clear, both of these occur on the same SwingWorker class for me - it depends on the input data, and the type of processing the caller wanted.
Is there a proper way to handle this? Obviously I can intentionally delay or yield the background processing thread so that a smaller number might arrive each time, but this doesn't feel like the right solution to me.
You can try publishing smaller chunks of the results.
If that does not help, you might also consider throttling the UI updates instead of the computation. You could moderate the UI update by having process store the NodePairs it receives into a blocking queue:
#Override
protected Void doInBackground() {
this.treeModelUpdater.execute();
// Omitted; performs variable processing to build a tree of address nodes.
}
#Override
protected void process(List<NodePair> chunks) {
this.queue.addAll( chunks ); // a blocking queue
}
#Override
protected void done() {
// Null Object as sentinel value to unblock TreeModelUpdater
// and signal it to end doInBackground.
this.queue.put( new NullNodePair() );
}
TreeModelUpdater (this.treeModelUpdater) would then be a subordinate SwingWorker implementation whose doInBackground method retrieves and publishes the NodePairs from the queue in a throttled manner.
As far as I know the process method is primarily to update the UI with the results of background processing. In the case of 1Mio chunk it makes me wonder where all that info would go on the screen? :-)
I would batch the chunks together in a sizable List and send that over for processing so that at least the synchronisation part is reduced significantly.
If you need to be able to display 1Mio dataelements using controls then performance is going to suffer anyway, unless you use lazy representation techniques, i.e. only instantiate the stuff which is actually visible. In this case the process routine will no longer be overloaded.