Reactive Programming ist zur Zeit in. Es verspricht ein einfacheres implementieren von asynchronen Abläufen indem Informationen als Events (oder Messages) von einer Komponente auf die andere übertragen werden können. Für einen kleinen Test von Bluetooth Fähigkeiten implementierte ich eine Android App die als Server oder als Client eingesetzt werden kann und die Daten vom Client zum Server sendet. Da die Kommunikation mit dem Bluetooth Adapter asynchron in einem eigenen Thread laufen muss, kann das reaktive Paradigma hier eingesetzt werden, um die UI-Komponente von der Kommunikations-Komponente zu entkoppeln.
Die App hat nur eine einzige Activity die den Server oder den Client startet und die Ausgabe der Kommunikation macht. Um die Lesbarkeit des Codes zu verbessern benutze ich Android Annotations (http://www.androidannotations.org). Das nächste Bild gibt einen Überblick der Programmdateien.
Für den reaktiven Teil der App setze ich den EventBus von Google Guava (http://code.google.com/p/guava-libraries/) ein. Damit der Bus mit Android Annotations injected werden kann kreiere ich eine eigene annotierte Klasse BtEventBus.
Der Bluetooth Server (im nächsten Bild) öffnet beim Initialisieren auf Zeile 39 ein Server Socket. Wird die App als Server benutzt so wird die startListening() Methode aufgerufen, die dank der @Background Annotation (Zeile 45) in einem eigenen Thread läuft. Der Server wartet dann auf eine eingehende Verbindung (Zeile 52) und liest dann anschliessend periodisch die eintreffenden Bytes aus (Zeilen 53 – 68). Diese sollen dann an die UI weiter gegeben werden. Auch wenn etwas mit der Bluetooth Verbindung schief läuft, dann soll der Benutzer darüber informiert werden.
Diese Benachrichtigung sollte auf keinen Fall im BtServer drin geschehen, denn dadurch würde die Kommunikations-Komponente an die UI gekoppelt werden (z.B. durch eine Referenz auf die MainActivity) und die App würde weniger wartbar. Stattdessen können wir der UI eine Meldung schicken, dass sich etwas Interessantes ereignet hat. Dies ist die Grundidee von Reactive Programming.
Klassisch würde man dazu das Observer Pattern umsetzen, d.h. zwei Interfaces (Subject und Observer) deklarieren und dann bei den entsprechenden Klassen implementieren. Viel einfacher geht es aber mit dem EventBus, der auf Zeile 28 und 29 injected wird. Um noch flexibler zu sein, habe ich dessen Aufruf nochmals in einer Methode signal() (Zeilen 75-77) gekapselt. Somit könnten wir, die Implementation des Informationsaustausches später leicht ändern und z.B. Logging einfügen, oder einen anderen EventBus mit anderer Signatur verwenden. Um die Meldung abzusetzen reicht es ein Objekt einer selbst definierten Klasse (optimalerweise mit dem Namenszusatz Event) an die Methode post() zu übergeben. Die Klasse kann Informationen (hier eine Nachricht) in eigenen Feldern speichern.
Um die Meldungen in der MainActivity zu empfangen reicht es eine Methode zu deklarieren, die einen Parameter vom Typ BtEvent hat und sie mit @Subscribe zu annotieren (Zeilen 52 – 56). Die Methode ist hier ausserdem mit @UiThread annotiert, damit die Ausgabe auf dem Ui-Thread geschieht. Ausserdem muss der Empfänger sich noch beim EventBus registrieren (Zeile 43).
Beim Empfang der Events sind wir aber keinesfalls auf die UI beschränkt: Jedes Objekt kann Events vom EventBus empfangen und ein Event kann auch von mehreren Objekten empfangen werden.
Durch den Einsatz des EventBus wird die Behandlung von asynchronen Abläufen erheblich vereinfacht. Zudem unterstützt er die Implemenierung der losen Kopplung zwischen den Komponenten.
Der Vollständigkeit halber ist unten der BtClient auch noch dargestellt.
Hi Thomas.
Interessant. @EBean hab ich bis jetzt übersehen. Sollte ich mir mal genauer anschauen.
Ich hab da auch eine Frage: Hat es einen Grund warum Du keinen Service für die Kommunikation verwendest?
Grüße
Martin