TaskMonitor - PropertyChange wird zweimal aufgerufen

hesk

Erfahrenes Mitglied
Hallo!

Ich habe eine SingleFrameApplication wo ich einen TaskMonitor regestriere.
Wenn ich nun einen Task ausführe, so wird der PropertyChangeListener zwei mal aktiviert.
Also er kommt zwei mal in "started" und am Ende zweimal in "done".

Hier das Beispielprogramm:

Java:
package swing;

import org.jdesktop.application.Application;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.Task;
import org.jdesktop.application.TaskMonitor;

public class TaskMonitorTest extends SingleFrameApplication
{
    /**
     * At startup create and show the main frame of the application.
     */
    @Override
    protected void startup()
    {
        FrameView main = new MainFrame(this);
        show(main);
    }

    @Override
    protected void shutdown()
    {
        // The default shutdown saves session window state.
        super.shutdown();

        // Now perform any other shutdown tasks you need.
    }

    /**
     * This method is to initialize the specified window by injecting resources. Windows shown in our application come
     * fully initialized from the GUI builder, so this additional configuration is not needed.
     */
    @Override
    protected void configureWindow(java.awt.Window root)
    {
    }

    /**
     * Main method launching the application.
     */
    public static void main(String[] args)
    {
        launch(TaskMonitorTest.class, args);
    }
    
    public class MainFrame extends FrameView
    {

        public MainFrame(Application arg0)
        {
            super(arg0);
            
            TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
            taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener()
            {
                public void propertyChange(java.beans.PropertyChangeEvent evt)
                {
                    String propertyName = evt.getPropertyName();
                    if ("started".equals(propertyName))
                    {
                        System.out.println("started");
                    }
                    else if ("done".equals(propertyName))
                    {
                        System.out.println("done");
                    }
                    else if ("message".equals(propertyName))
                    {
                        String text = (String)(evt.getNewValue());
                        System.out.println("test: " + text);
                    }
                    else if ("progress".equals(propertyName))
                    {
                        System.out.println("progress");
                    }
                }
            });
            
            TestTask test = new TestTask();
            System.out.println("Task wird gestartet");
            getApplication().getContext().getTaskService().execute(test);
        }
        
        private class TestTask extends Task<Void,Void>
        {
            
            public TestTask()
            {
                super(Application.getInstance());
            }
            
            @Override
            protected Void doInBackground() throws Exception
            {
                setMessage("Opening the file");
                Thread.sleep(2000);
                System.out.println("im Task");
                
                return null;
            }
            
            @Override
            protected void finished()
            {
                super.finished();
            }
        }
        
    }
}

Output:

Code:
Task wird gestartet
started
started
test: Opening the file
im Task
done
done
 
Schwer zu sagen, da ich nicht weiß, was "launch" macht.
Zum Prüfen könntest Du das Objekt und den aktuellen Thread (Thread.currentThread()) mit ausgeben, um zu erfahren, ob vielleicht zwei Deiner Objekte erzeugt werden.
 
Hallo,

wenn du den PropertyChangeListener an den TaskMonitor hängst bekommst du so wie es ausschaut die Property Change Events für den Monitor UND die einzelnen Tasks mit...

Ich denke was du eigentlich machen willst ist die Property Changes eines Tasks zu überwachen. Dazu könntest du einfach einen PropertyChangeListener am Task anstatt am TaskMonitor registieren. Dann bekommst du die State Changes wie gewünscht nur einmal mit.

schau mal hier:
Java:
package de.tutorials.training;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.SwingUtilities;

import org.jdesktop.application.Application;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.Task;
import org.jdesktop.application.TaskMonitor;

public class TaskMonitorTest extends SingleFrameApplication {
	/**
	 * At startup create and show the main frame of the application.
	 */
	@Override
	protected void startup() {
		FrameView main = new MainFrame(this);
		show(main);
	}

	/**
	 * Main method launching the application.
	 */
	public static void main(String[] args) {
		launch(TaskMonitorTest.class, args);
	}

	public class MainFrame extends FrameView {

		public MainFrame(Application app) {
			super(app);

			final TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
			

			TestTask test = new TestTask();
			test.addPropertyChangeListener(new PropertyChangeListener() {
				public void propertyChange(PropertyChangeEvent evt) {
					
					String propertyName = evt.getPropertyName();

					if ("started".equals(propertyName)) {
						System.out.println("started");
					} else if ("done".equals(propertyName)) {
						System.out.println("done");
					} else if ("message".equals(propertyName)) {
						String text = (String) evt.getNewValue();
						System.out.println("test: " + text);
					} else if ("progress".equals(propertyName)) {
						System.out.println("progress");
					}
				}

			});
			
			
			System.out.println("Task wird gestartet");
			getApplication().getContext().getTaskService().execute(test);
		}

		private class TestTask extends Task<Void, Void> {

			public TestTask() {
				super(Application.getInstance());
			}

			@Override
			protected Void doInBackground() throws Exception {
				// setMessage("Opening the file");
				Thread.sleep(2000);
				System.out.println("im Task");

				return null;
			}

		}

	}
}

Ausgabe:
Code:
Task wird gestartet
Dez 01, 2011 4:32:06 PM org.jdesktop.application.LocalStorage getId
Warnung: unspecified resource Application.id using TaskMonitorTest
Dez 01, 2011 4:32:06 PM org.jdesktop.application.LocalStorage getId
Warnung: unspecified resource Application.vendorId using UnknownApplicationVendor
started
im Task
done

Btw. mit Java 7 könntest du auch einfach switch mit Strings verwenden um deine if-Kaskade los zu werden:
Java:
...
			test.addPropertyChangeListener(new PropertyChangeListener() {
				public void propertyChange(PropertyChangeEvent evt) {
					switch (evt.getPropertyName()) {
					case "started":
						System.out.println("started");
						break;
					case "done":
						System.out.println("done");
						break;
					case "message":
						System.out.println("test: " + evt.getNewValue());
						break;
					case "progress":
						System.out.println("progress");
						break;
					default: /* ignore */
						;
					}
				}
			});
...

Gruß Tom
 
Kann das Beispiel gerade nicht testen, aber es wird schon der Grund sein warum es doppelt ausgegeben wird.

Aber was ich eigentlich wollte war: den TaskMonitor zu testen. Ich wollte wissen was das Ding macht und wie es funktioniert.
So wie ich es verstanden habe kann man der Applikation den TaskMonitor zuweisen und egal wo man in der Applikation dann per "getApplication().getContext().getTaskService().execute" einen Task aufruft, der TaskMonitor bekommt dies mit und gibt dann dementsprechende Sachen am Bildschirm aus.

Verstehe ich das so richtig?
 
Hallo,

hast du dir schon die Doku unter: http://www.jarvana.com/jarvana/view...ar!/org/jdesktop/application/TaskMonitor.html durchgelesen?

Scheinbar ist der TaskMonitor wirklich nur dazu da die aktuell laufenden Tasks und den Tasks im "Vordergrund" zu halten / zu unterscheiden. Der TaskMonitor ist IMHO für eine "direkte" Task Überwachung ohne etwas "unterbau" nicht gemacht...

...ich hab mir mal schnell selbst eine Task Visualisierung gebaut:
Java:
package de.tutorials.training;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.TimeUnit;

import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.table.AbstractTableModel;

import org.jdesktop.application.Application;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.Task;
import org.jdesktop.application.TaskMonitor;

public class TaskMonitorTest extends SingleFrameApplication {

	@Override
	protected void startup() {
		FrameView main = new MainFrame(this);
		show(main);
	}
	
	public static void main(String[] args) {
		launch(TaskMonitorTest.class, args);
	}

	public class MainFrame extends FrameView {

		private TaskVisualizer taskVisualizer;

		public MainFrame(Application app) {
			super(app);

			taskVisualizer = new TaskVisualizer(getContext().getTaskMonitor());

			setComponent(taskVisualizer);
						
			Timer taskGenerator = new Timer(1000,new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					if(getContext().getTaskMonitor().getTasks().size() < 6){	//limit to max 6 task at once
						getContext().getTaskService().execute(new TestTask("Task_" + Integer.toString(System.identityHashCode(e),36)));	
					}
				}
			});
			taskGenerator.setCoalesce(true);
			taskGenerator.setRepeats(true);
			taskGenerator.start();
		}

		private class TestTask extends Task<Void, Void> {

			public TestTask(String title) {
				super(Application.getInstance());
				setTitle(title);
			}

			@Override
			protected Void doInBackground() throws Exception {
				for(int i = 1; i <= 3; i++){
					setMessage("Step " + i);
					TimeUnit.MILLISECONDS.sleep((long) (Math.random() * 3000));
				}
				return null;
			}

			@Override
			protected void succeeded(Void arg) {
				System.out.println("succeeded " + getTitle());
			}
		}
	}

	public static class TaskVisualizer extends JComponent {

		private static final long serialVersionUID = 1L;
		
		private TaskMonitor taskMonitor;
		
		private JTable table;
		
		private PropertyChangeListener taskMonitorPropertyChangeListener;

		public TaskVisualizer(TaskMonitor taskMonitor) {
			attach(taskMonitor);
			createTaskVisualization();
		}

		private void createTaskVisualization() {
			table = new JTable(new TaskTableModel(taskMonitor));
			setLayout(new BorderLayout());
			add(new JScrollPane(table), BorderLayout.CENTER);
		}

		private void attach(TaskMonitor taskMonitor) {
			this.taskMonitor = taskMonitor;
			this.taskMonitorPropertyChangeListener = new PropertyChangeListener() {
				@Override
				public void propertyChange(PropertyChangeEvent evt) {
					refresh();
				}
			};
			this.taskMonitor.addPropertyChangeListener(this.taskMonitorPropertyChangeListener);
		}

		private void refresh() {
			table.updateUI();
		}
	}

	public static class TaskTableModel extends AbstractTableModel {

		private static final long serialVersionUID = 1L;

		private final TaskMonitor taskMonitor;
		
		private String[] columns = { "ID", "Title", "State", "Message" };
		
		public TaskTableModel(TaskMonitor taskMonitor) {
			this.taskMonitor = taskMonitor;
		}

		@Override
		public int getRowCount() {
			return this.taskMonitor.getTasks().size();
		}

		@Override
		public int getColumnCount() {
			return columns.length;
		}
		
		@Override
		public String getColumnName(int column) {
			return columns[column];
		}

		@Override
		public Object getValueAt(int rowIndex, int columnIndex) {
			Task<?,?> task = this.taskMonitor.getTasks().get(rowIndex);

			Object value = null;
			switch (columns[columnIndex]) {
			case "ID":
				value = System.identityHashCode(task);
				break;
			case "Title":
				value = task.getTitle();
				break;
			case "State":
				value = task.getState();
				break;
			case "Message":
				value = task.getMessage();
				break;
			default:
				throw new UnsupportedOperationException("XXX");
			}

			return value;
		}
	}
}
Vielleicht hilfts dir ja weiter...

Gruß Tom
 
Finde es immer wieder beeindruckend wie du schnell mal was zusammen bastelst:)

Ja, das hilft mir auf alle Fälle weiter. Vielen Dank:)
 
Zurück