3.3. Der Ui Thread Access

Wie in anderen UI Frameworks (wie Swing oder Swt) gibt es auch in jowidgets einen UI Thread, in welchem alle UI Events dispatched werden. Alle Modifikationen an Widgets oder deren Models müssen in diesem Thread erfolgen. Reagiert man auf Events, welche durch Nutzereingaben ausgelöst wurden, befindet man sich bereits automatisch im UI Thread. Dabei ist, wie auch bei anderen UI Frameworks, darauf zu achten, den UI Thread nicht für lange Berechnungen zu blockieren, weil ansonsten keine Events mehr verarbeitet werden können und die Oberfläche für diese Zeit einfriert.

Operationen die potentiell lange dauern können, wie Beispielsweise das Aufrufen eines Service, sollten daher immer in einem eigenen Thread stattfinden.

Will man aus einem anderen Thread heraus wieder Methoden auf UI Elementen aufrufen, bietet die Schnittstelle IUiThreadAccess dafür die folgenden Methoden:

    void invokeLater(Runnable runnable);
    
    void invokeAndWait(Runnable runnable) throws InterruptedException;

Die Methode invokeLater() führt das übergebene Runnable zu einem späteren Zeitpunkt im Ui Thread aus. Nachdem die Methode zurückkehrt, kann man jedoch nicht davon ausgehen, dass das Runnable bereits ausgeführt wurde.

Die Methode invokeAndWait() führt auch das Runnable im Ui Thread aus, blockiert aber so lange, bis das Runnable ausgeführt wurde. Diese Methode ist mit höchster Vorsicht zu verwenden. Bei falscher Verwendung erzeugt man dadurch sehr schnell einen Deadlock. Statt blockierenden Methodenaufrufen sollte man besser mit Callback’s arbeiten.

Beide Methoden können in jedem beliebigen Thread aufgerufen werden.

Um zu prüfen, ob der aktuelle Thread der UI Thread ist, kann man die folgende Methode verwenden:

    boolean isUiThread();

Der Aufruf:

   IUiThreadAccess uiThreadAccess = Toolkit.getUiThreadAccess();

muss immer im UI Thread erfolgen. Dies liegt unter anderem daran, dass es im Web Kontext mehrere UI Threads (einer pro User Session) existieren, und ein beliebiger Thread nicht wissen kann, welcher UI Thread verwendet werden soll.

In der Praxis übergibt man die IUiThreadAccess Instanz einfach an den anderen Thread. Folgendes Beispiel zeigt, wie man das einfach mit Hilfe des Ausführungsstacks machen kann:

  1      //Add an listener to the button that does a long lasting calculation
  2      button.addActionListener(new IActionListener() {
  3          @Override
  4          public void actionPerformed() {
  5  
  6              //this will be invoked in the ui thread
  7              final IUiThreadAccess uiThreadAccess = Toolkit.getUiThreadAccess();
  8  
  9              //execute the service calculation in an service thread
 10              executorService.execute(new Runnable() {
 11  
 12                  @Override
 13                  public void run() {
 14                      //this will be invoked in the service thread
 15                      final ServiceResult result = longLastingService.doLongLastingCalculation();
 16  
 17                      uiThreadAccess.invokeLater(new Runnable() {
 18                          @Override
 19                          public void run() {
 20                              //this will be executed in the ui thread
 21                              serviceResultWidget.showResult(result);
 22                          }
 23                      });
 24                  }
 25  
 26              });
 27          }
 28      });

Hinweis: Das obige Beispiel wurde bewusst vereinfacht. Es fehlen u.A. wichtige Aspekte wie Fehlerbehandlung oder das Abbrechen der Berechnung.


Siehe auch PDF Version dieses Dokuments, Jowidgets API Spezifikation