Swing, Passive View and Long running tasks - java

I'm trying to implement a Passive View based gui system in swing. Basically i want to keep my view implementation (the part that actually contains swing code) minimal, and do most of the work in my Presenter class. the Presenter should have no dependency on swing and also should "run the show", i.e. tell the view what to do and not vice versa.
I run into problems when dealing with long running tasks, and threads separation in general. I want GUI updates to run on the EDT, and the presenter logic to run on a different thread. If i want the presenter to update some part of the GUI it's pretty easy, i write something like that:
public interface View {
void setText(String text);
}
public class Presenter {
View view;
...
public void setTextInVIew() {
view.setText("abc");
}
}
public class MyFrame implements View {
JTextField textField;
...
public void setText(final String text) {
SwingUtilities.InvokeLater(new Runnable() {
public void run() {
textField.setText(text);
}
});
}
}
However, when the GUI is to inform the presenter that some action has occurred, i want to switch out of the EDT in react to it in a different thread:
public class Presenter {
...
public void buttonPressed() {
// shouldn't run on EDT
}
}
public class MyFrame implements View {
JButton button;
public MyFrame() {
...
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
presenter.ButtonPressed();
}
});
}
}
since the actionPerformed code is running from the EDT, so will the presenter.buttonPressed. I know swing has the concept of SwingWorker - running tasks in a different thread, however it looks like i'll have to insert swing code into my presenter, and the view is running the show. Any ideas how to solve this?

you could do something like the following, which will keep your GUI code in place and simply perform the work to get out of the EDT:
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
SwingWorker sw = new SwingWorker() {
public Object doInBackground(){
presenter.ButtonPressed();
return null;
}
};
sw.execute();
}
});

You might be interested in the Task API to avoid all the boilerplate. Otherwise akf's solution looks fine (although no need to create a variable for SwingWorker, you can just new and execute an anonymous one).

Another approach to the SwingWorker solution outlined by others is to use an event bus with thread affinity. I actually think that this might be the best option for the type of decoupling you are going for.
Check out: EventBus
there are other implementations of the bus architecture, but EventBus is popular.
-- update --
So EventBus is going to provide a very clean way of proxying from non-EDT to EDT (a lot nicer than tons of explicit calls to SwingUtilities.invokeLater() - but basically doing the same thing. Although an EventBus is able to bundle up many notifications and have them hit in a single EDT runnable, so performance will be better).
But this doesn't address the need to proxy events from the EDT and get them running on a worker thread. There is a ThreadSafeEventService class in EventBus that could probably be used as the foundation for such a beast - it could be coupled with an ExecutorService, for example, to process certain event registrations for certain listeners.
I guess the key in all this for me is that whatever solution you come up with, it should try to encapsulate the spinning on/off the EDT
BTW - What you are asking about here is really similar to Microsoft's Apartment threading model.

OK - I've got another option for you: Spin
Ultimately, all of these solutions are proxying calls between threads. I think the goal is to find a solution that doesn't require gobs of boilerplate code on your end. You could, for example, wire all of your listeners so they check to see if they are on an appropriate worker thread, then proxy to an ExecutorService if not. But that's a major hassle. Much better to get that proxying occuring in the layer between your business and view objects - the binding/listener/whatever you want to call it layer.

Related

Is it better to use done method or a change listener on SwingWorker?

I have a task that when done it update a swing GUI telling that is done. What I saw is that you can use done() method or attach a PropertyChangeListener and listen for the change to done status.
What is better to use and why? Or are they the same?
For example, this:
public class Foo implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())
&& (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) {
this.updateTheGuiAndOtherThings();
}
}
}
or this:
public class W extends SwingWorker {
protected Boolean doInBackground() throws Exception {...}
protected void done() {
otherClass.updateTheGuiAndOtherThings();
}
}
In my case isn't necessary better efficiency, I ask more for correct code writing.
Is it better to use done method or a change listener on SwingWorker?
Generally speaking both ways are correct and equivalent.
However the main advantage of using PropertyChangeListener is you can have several listeners attached to the SwingWorker which allows you to split tasks in small code units rather than have a single done() block of code. This is useful for example if you have to update several Swing components and you want to keep those updates cohesively separate.
In addition using listeners reduces coupling between the SwingWorker and GUI components: it has no knowledge about what will happen when the background thread finishes and it's ok. By overriding done() method this won't be true anymore.
An important thing to do - when either listening for StateValue.DONE or overriding done() method - is to call get() method in order to catch and treat any exception that may be thrown during doInBackground() processing. See this Q&A related to this point.
For the rest there is no major difference. I'd go with listeners just for scalability.
Update
Based on #mKorbel's comments below, you might want to take a look to this topic too: Is a swingWorker guaranteed to throw a state property change event on completion? and also even recosinder use a SwingWorker. I have had no problems personally but it's good to be aware about possible bugs related to the multi-threading nature of this matter.

Swing application multithread design patterns and best practices

I've been reading a lot of SO answer and questions but I never asked anything before.
My question is about desing patterns and best practices in Swing application.
Suppose you have a Swing application with a GUI class with a JLabel and another class (not an inner class of the previous) which extends Thread and perform some network operations (basically it periodically fetch resources from a web API to check if a given value appear).
When a certain value is fetched by the second class I need to update the JLabel of the firt class. I'm perfectly aware this should be done in the EDT using invokeLater(), my question is how to handle the access from the background Thread to the JLabel.setText() method.
As far as I know I see three solution:
provide a static getter in the GUI class and call it insite a SwingUtilities.invokeLater() in the Thread class
provide a static method inside the GUI class which internally calls SwingUtilities.invokeLater() and access that method (say MyGui.updateTheLabel()) from the Thread class
passing a reference of the JLabel to the Thread constructor and use that reference to update the label with SwingUtilities.invokeLater()
Which one of this solution is better? Are there particular design patterns meant to solve this issue. I find it ugly to put SwingUtilities.invokeLater() everywhere I want to update the GUI or creating static getters around.
Thank you :)
The networking thread should not know about JLabel. Its duty is to load some data from network. Exposing that data on a screen is another task, and should be made with a special UI class. That class should have some method like (update(byte[]), which internally calls invokeLater. An instance of that UI class should be passed to the networking thread at creation time, and that thread should periodically call update method.
To perform tasks in background and updating UI elements in Swing application you can use SwingWorker class.
I usually define runnables for the tasks I'll be performing on the GUI, and create these when needed. Outsiders need not know how the updates are performed, they just use the GUI's exposed API.
Example:
interface NetworkUpdateListener {
void updateFetched(String newText);
}
class Gui implements NetworkUpdateListener {
private JLabel label;
// ...
#Override
public void updateFetched(String newText) {
SwingUtilities.invokeLater(new LabelUpdater(newText));
}
private final class LabelUpdater implements Runnable {
private final String text;
LabelUpdater(String s) { text = s; }
#Override
public void run() { label.setText(text); }
}
}
Somewhere else, from another thread:
NetworkUpdateListener listener;
// ...
listener.updateFetched(text);

What's proper way to make my own events in java

I'm student and I'm working on project with few of my friends. My task is to make something like class library. Classes in this library should provide API for my friend who must make GUI part of application. GUI could be made by any toolkit (Swing, JavaFX, SWT, AWT, all should work, in fact, it should work even if there is no GUI). I need to make class that waits for data to arrive from network. I don't know when data will arrive, and UI must be responsive during waiting, so I put that in different thread. Now problem is how to make GUI respond when data arrive. Well, I tought that this is asynchronous event and GUI should register event handlers, and I should call that methods when event happens. I proposed this solution:
interface DataArrivedListener{
void dataArrived(String data);
}
class Waiter{
private DataArrivedListener dal;
public void setDataArrivedListener(DataArrivedListener dal){
this.dal = dal;
}
void someMethodThatWaitsForData(){
// some code goes here
data = bufRdr.readLine();
//now goes important line:
dal.dataArrived(data);
// other code goes here
}
}
My question is:
Should I replace "important" line with something like this:
java.awt.EventQueue.invokeLater(new Runnable(){
#Override
public void run(){
dal.dataArrived(data);
}
});
Or something like:
javafx.Platform.runLater(new Runnable(){
#Override
public void run(){
dal.dataArrived(data);
}
});
Or maybe I should do something completely different?
Problem is that I'm not sure which of this will work for any type of UI. If it's GUI, dataArrived() could potentialy make changes to GUI and no matter what type of GUI it is, this changes should be drawn on screen properly. I also think that it is better if I do "invoke this code later" so that my someMethodThatWaitsForData() method could trigger event and continue on with it's on work.
I appreciate your help.
Here's an Event Listener article I wrote a while back. The article explains how you write your own event listeners.
You're correct in that you want to write your own event listeners if you want your library to work with any GUI.
I'm most familiar with Swing, so yes, you'll have GUI code that looks like this:
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent event){
dal.buttonPressed(data);
}
});
If you want it to be completely agnostic to what GUI is being used the only real solution is to let the receiver handle it in dataArrived. Since every toolkit has its own implementation all you can really do to make it work with any toolkit is to disregard it. Otherwise what you will actually end up with is a list of "supported toolkits" and a case for each one.
If you just want dataArrived to be executed away from someMethodThatWaitsForData then you could make your own dispatch thread or make a new thread each time.
If you want to be truly independent of any front-end system, I would recommend creating two threads. The first is your Waiter, which will just listen for events and put them into a Queue of some sort (see the "All Known Implementing Classes" section). The second will invoke the data listener or listeners whenever the queue is not empty.
The concept of invoking a Runnable in the background is kind of deprecated since the invention of the concurrent package. The main reason that this was done in earlier days, is that the GUI code needs to be executed in a different thread, to guarantee that it stays responsive, even if the main thread is busy doing some calculations, but actual multi-threading was still in its very early days. The resulting invokeLater concept works, but comes with a strong creation overhead. This is especially annoying if you frequently have to do minor things, but each time you need to create an entire new Runnable, just to get that event into the Swing thread.
A more modern approach should use a thread-safe list, like a LinkedBlockingQueue. In this case any thread can just throw the event into the queue, and other listener/GUI-Event-handlers can take them out asynchronously, without the need of synchronization or background Runnables.
Example:
You initialize a new Button that does some heavy calculation once it is pressed.
In the GUI thread the following method is called once the button is clicked:
void onClick() {
executor.submit(this.onClickAction);
}
Where executor is an ExecutorService and the onClickAction a Runnable. As the onClickAction is a Runnable that was submitted once during Button creation, no new memory is accessed here. Let's see what this Runnable actually does:
void run() {
final MyData data = doSomeHeavyCalculation();
dispatcher.dispatch(myListeners, data);
}
The dispatcher is internally using the LinkedBlockingQueue as mentioned above (the Executor uses one internally as well btw), where myListeners is a fixed (concurrent) List of listeners and data the Object to dispatch. On the LinkedBlockingQueue several threads are waiting using the take() method. Now one is woken up as of the new event and does the following:
while (true) {
nextEvent = eventQueue.take();
for (EventTarget target : nextEvent.listeners) {
target.update(nextEvent.data);
}
}
The general idea behind all this, is that for once you utilize all cores for your code, and in addition you keep the amount of objects generated as low as possible (some more optimizations are possible, this is just demo code). Especially you do not need to instantiate new Runnables from scratch for frequent events, which comes with a certain overhead. The drawback is that the code using this kind of GUI model needs to deal with the fact that multi-threading is happening all the time. This is not difficult using the tools Java gives to you, but it is an entire different way of designing your code in the first place.

does swing view needs synchronized methods if its set by new threads in controller

There is actually more than 1 question.
Given Model View and Controller. (Mine are coupled a lot - View knows its Controller, and Controller knows View.)
Does new threads in Controller can be fired in basic manner - with the new Runnable(){ (...) run(){}} or it is required to do in some "swing way", to make it properly? Maybe with Timer or invokeLater()?
Second thing is - assuming that new thread has started - when it operates directly on view, setting some JTextFields (and so on) - do methods such as setThatTextFieldWithNewValue(msg) need to be synchronized as a result of being called from need thread? If so - is there any better approach that gives less coupling and less spend time thinking about needed synchronization?
there are a few ways how is possible to create, manage and notify MVC, for better help sooner post an SSCCE
Runnable#Thread is very confortable, stable and clear way, but I'd suggest to wrap all output to the Swing GUI into invokeLater, including thread safe methods as setText, append e.g. are ..
as Kumar Vivek Mitra (+1) metioned there is SwingWorker, but required deepest knowledge about Java essential classes, some trouble are there with exceptions recycle how to get exception from SwingWorker
about MVC maybe will help you my similair question
Swing is not Thread-Safe
1. The UI thread is the Event Dispatcher Thread, which is responsible for the Gui work.
2. Try working with Non-Ui threads outside the UI thread.
3. Yes offcourse you can fire a thread from within the UI thread, but its advisable to keep it out of
the UI thread, else the GUI may seems non-responsive.
(ie. the Non-UI work on the Non-UI thread OUT of the UI thread which is responsible for the UI Work)
4. Well there is a swing way too... use SwingWorker, this handles the synchronization between UI and Non-UI thread.
Edited part:
// PLEASE NOTE ITS NOT GOOD TO ADD COMPONENTS DIRECTLY ON THE FRAME/JFRAME, BUT I AM DOING THIS JUST TO SHOW, WHAT I MEANT.
public class MyClass extends JFrame{
private final JButton b;
public MyClass(){
this.setSize(300,300);
this.setComponent();
this.setHandler();
}
public void setComponent(){
b = new JButton("Click");
this.add(b);
}
public void setHandler(){
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// Do whatever you want...
}
});
}
public static void main (String[] args) {
EventQueue.invokeLater(new Runnable(){ // UI THREAD
public void run(){
MyClass s = new MyClass();
s.setVisible(true);
}
});
}
}
Main method is short lived in Swing, The main method() schedules the Construction of GUI to the Event Dispatcher Thread (EDT), and then quits. So its EDT responsibility to handle the GUI. So its always advisable to keep the Non-UI work on the Non-UI thread away from EDT.
Anything in swing has to run on the EventQueue. If you have a method called from swing it will already be running there (as in an Action listener). If you don't know if you're on the event queue, EventQueue.isDispatchThread() will tell you. When you know you're not, reference a swing class or method using EventQueue.invokeLater() or invokeAndWait if you need to see results. (This must be done from the main method.)
Be very careful about this; you have to check your code. If not, my experience is that the swing UI will be just a little bit flakey, with the occasional unreproducable oddity. There's no easy way around eyeballing each line of code.
Actually, there is. Do everything on the EventQueue, then you won't have to worry. You're probably not doing a whole lot of work outside swing anyway. If you are, it's probably worth the loss of speed to avoid multithreading problems. If your non-swing work is extensive but simple, use the SwingWorker class. It gives you an extra thread under highly controlled conditions and should save you a lot of grief.
Your classes (View and Controller) are independent of threads, and should work just fine all running in one thread. Don't confuse classes and threads. (I'll admit, I'd be tempted to have the Controller firing off threads in all directions, but you have to be prepared to be very careful and know everything there is to know about multithreading.)
If you do multithread, the EventQueue can be a bit handy because you don't have to protect fields referenced only there--it's an island of single threading in a dangerous sea. On the other hand, don't do any synchronization there; you'll block your UI. You can launch threads from there and you may have to just to avoid blocking. (Once you start multithreading, it's hard to stop.)
The easiest way would be:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Run your code here.
}
});
For more complex tasks (send process chunks to ui thread, respond to jobFinished):
new SwingWorker<String, String>() {
#Override
protected void done() {
}
#Override
protected void process(List<String> arg0) {
}
#Override
protected String doInBackground() throws Exception {
}
}.execute();

Swing, how to properly update the UI

What is the right way to update the UI after doing some operations on Swing?
For example, after clicking a button, a method is called that may be almost instant or take some seconds. In fact, all the applicaton logic is done remotely through a web service, so it's normal to wait a little bit for the application to respond.
My eventhandler for a button may look like these:
myButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
//callWebService();
//do stuff
//updateUI(); // <----- repaint? revalidate? what?
}
});
My current implementation calls the updateUI method which internally call validate() and repaint() to the parent component that holds the UI. This works, but sometimes I can see the screen flickering. Am I doing it wrong? Is there a better way to do it?
The right way would be to use SwingWorker, but if you want to do it manually you'll have to implement the following pattern:
#Override public void actionPerformed(java.awt.event.ActionEvent evt) {
new Thread() {
#Override public void run () {
//callWebService();
//do stuff
SwingUtilities.invokeLater(new Runnable(){
#Override public void run() {
//updateUI(); // <----- repaint? revalidate? what?
}
});
}
}.start();
}
For the repaint/revalidate question, normally call revalidate() then repaint(). this is, of course, only valid for component that you manually draw. For components that you reuse, just call their value change methods.
I'd personally use SwingWorker for this, despite some of the other comments / answers:
Despite the fact keeping the UI responsive isn't part of the original question, it's good practice to do this anyway (I can't think of a single good reason to lock up the EDT with lengthy processing.)
It provides a done() method that can be implemented which will be executed on the EDT by default when the task is complete, saving the need for manually wrapping up things in invokeLater()
It's more extensible, providing the framework to allow information like progress to be added easily later if it's so desired.
I've seen a lot of SwingWorker hate in general recently, and I don't understand why. It's a nicely designed, extensible class specifically for purposes such as this that works well. Yes, you could wrap things up in threads and launch them and have them wrap other methods up in invokeLater(), but why reinvent the wheel when there's a better one available for free?
Take the long running task to a different thread. Send events back to the AWT Event Dispatch Thread (EDT) to update the GUI with java.awt.EventQueue.invokeLater.
You shouldn't normally have to do anything : if you use the swing components methods, or the methods of their model, the necessary events are fired and the GUI should update itself automatically.
This won't be the case if you define your own models (and forget to fire the necessary events, but then it's a bug in your models, and it should be fixed there.

Categories