Dies ist eine kurze Zusammenfassung, in der das Verhalten von Background-Threads in MAF im Zusammenspiel mit dem Kontext eines Features beschrieben wird.

Background Threads – Best Practices

Als best practice wird angesehen, wenn man in einer mobilen Anwendung die intensiven Arbeiten auf einen neuen Background-Thread auslagert und nur das Ergebnis der Berechnung auf dem primären Thread anzeigt. Dies wird hauptsächlich angewendet, damit die Benutzeroberfläche des Anwenders nicht einfriert bis die eigentliche intensive Arbeit abgeschlossen ist. Die Arbeit kann im Hintergrund durchaus Sekunden bis Minuten dauern.

Einen Background-Thread kann man genauso wie in Java starten, da MAF auch Java für die Backend-Logik verwendet. Jedoch ist es ratsam einen Thread Pool zu verwenden der über eine limitierte Anzahl an parallelen Threads (idealerweise 1) und einem Queuing für das Ausführen der Threads in diesem Pool verfügt. Dies verhindert eine Überlastung des Systems durch die Erzeugung zu vieler paralleler Threads.

Für diese Aufgabe kann der ThreadPoolExecutor verwendet werden, welcher einen Built-in Queuing Mechanismus beinhaltet.

Man instanziiert diesen wie folgt:

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILISECONDS, new LinkedBlockingQueue<Runnable>());

Nach der Java Docs sind die Parameter folgendermaßen beschrieben:

[dt_code]corePoolSize – the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
maximumPoolSize – the maximum number of threads to allow in the pool
keepAliveTime – when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
unit – the time unit for the keepAliveTime argument
workQueue – the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.[/dt_code]

Im Grunde erstellst man einen Thread Pool mit einer Kapazität von 1. Alle anderen Threads, die zur Ausführung angestoßen werden sind landen in der Warteschlange. Die Warteschlange ruft man mit der getQueue() Methode des Executor auf.

Kontext der Features bei Nutzung eines Background Thread

Man verliert den Kontext des Features von dem der Background-Thread gestartet wurde, wenn ein neuer Background Thread erstellt wird. Der Feature Kontext des Threads wird zurückgesetzt auf das erste Feature in der Feature Referenzliste (wie es in maf-application.xml angezeigt wird). Beispiel: Wenn man einen neuen Background Thread startet – durch beispielweise eine Backing Bean Methode – aus dem Feature Departments so erhält man im Background-Thread mit dem Aufruf von AdfmfJavaUtilities.getFeatureId() nicht “Departments” als String zurück. Stattdessen bekommt man die ID des ersten Features welches in der maf-application.xml definiert wurde.

Auch eine Navigation im Background-Thread mit AdfmfContainerUtilities.gotoFeature(String featureId) ändert den Kontext nicht im primären Thread bzw. dem Frontend (die aktuelle Oberfläche des Benutzers wird nicht verändert). Das heißt konkret, im obigen Beispiel, dass die Oberfläche trotz Navigation im Background-Thread nicht von der Departments Seite wegnavigiert.

Interessanter Weise sind auch die Bindungs der unterschiedlichen Threads separiert. Es werden seperate Instanzen angelegt, was bedeutet, dass selbst wenn man mit dem Background-Thread und dem primären Thread zum gleichen Feature navigiert, keine Änderungen des einen Threads im anderen sichtbar werden.

Tipp: Man kann mit AdfmfJavaUtilities.isPrimaryRequestThread() überprüfen, ob ein Thread der in der Oberfläche laufende ist oder ein Background-Thread.