Jeder der irgendwann versucht hat Daten von einem Dialog zur übergeordneten Activity/Fragment zu übertragen, kennt den Schmerz den man bei der Umsetzung verspürt, die Zeit die es benötigt die benötigten Elemente einzubauen und das nervige Verhalten der Listener.
Jetzt stellt euch vor, es würde euch jemand die Arbeit ersparen den Listener zu bauen, einzupflegen und ihn an der entsprechenden Stelle auf zu rufen. Gut, die ersten zwei Sachen kann das Framework erfüllen was ich euch heute vorstellen möchte… zum letzten Punkt: bisschen müssen wir dann doch noch schreiben.
Der “normale“ Ablauf:
Natürlich gibt es unter euch sicherlich schon einige die den EventBus kennen und schon nutzen. Dennoch gehe ich davon aus, dass jeder der mal eine Kommunikation zwischen Activity/Fragment und Dialog aufbauen wollte, folgenden Ablauf gewählt hat:
1. Eine Listener-Klasse bauen.
2. Der Dialog-Klasse einen Member hinzufügen der den oben gebauten Listener beherbergt.
3. Getter und Setter generiert/schreibt
4. Dem Dialog nach dem instanziieren in der Activity/Fragment über den Setter einen Listener hinzufügen und die entsprechenden Callback-Methoden überschreiben und mit Code füllen (was soll mit dem übergebenen Infos passieren?)
Ihr kennt Otto – jeder kennt Otto!
Sicherlich kommt bei dem Namen Otto bei vielen der Gedanke, es hätte was mit dem Deutsche Komiker Otto Walkes zu tun. Tut es nicht!
Dennoch behaupte ich, dass ihr den Charakter, der dem Framework seinen Namen gegeben hat, zu 100% kennt. Es handelt sich um Otto, den (Schul-)Busfahrer von den Simpsons! Ihr wisst schon…der coole Kerl der immer seine Kopfhörer auf den Ohren hat :)
Bus fahren ist das neue beamen!
Bus – oder sagen wir lieber EventBus – ist das Zauberwort dass zu Otto passt. Der Ablauf ist ziemlich simpel. Das Ganze funktioniert mit zwei Komponenten. Dem Empfänger, in Form einer Funktion die vor ihren MethodenKopf eine @Subscribe-Annotation ziert und auf der anderen Seite der Sender, der jeden kennt der Nachrichten empfangen möchte.
Der Sender ist ein zentraler Punkt, der alle Empfänger kennt und sobald eine Nachricht eintrifft sie an die entsprechenden Stellen innerhalb der App weiterleitet. Damit der Sender aber alle Empfänger kennt, müssen sich diese vorher bei dem Sender (EventBus) registrieren. Dieser agiert wie ein Dirigent oder Lotse, der die Nachricht an den entsprechenden Empfänger weiterleitet.
Ein kleines Beispiel:
In einem Dialog trage ich einen Wert – sagen wir in ein EditText mit nur Zahlen – ein, den ich in ein entsprechendes Feld im Fragment einfügen möchte, was “unter” dem Dialog liegt. Dafür erzeuge ich in der Fragment-Klasse ein Event (interne Klasse) das ich “IntegerValueEvent” nenne:
public class IntegerValueEvent() { final int mValueFromDialog; public IntegerValueEvent(final int inValueFromDialog) { mValueFromDialog = inValueFromDialog; } public int getValueFromDialog() { return mValueFromDialog; } }
So, nun haben wir die EventKlasse erzeugt. In dieser Eventklasse, kann man alles “zwischenspeichern” was man möchte.Leider wissen wir aber nicht was wir damit anfangen sollen…
Aushilfe für dieses Problem, bietet die Annotation @Subscribe, die das Framework liefert. Diese Annotation wird vor eine Funktion/Methode gepackt so dass sie Events entgegen nehmen kann. Welche Events?
Die, die wir im Dialog abfeuern, wenn der User auf OK klickt:
Button okButton = (Button) view.findViewById(R.id.button_ok); okButton.setOnClickLister(new OnClickListener() { public void onClick(View inView) { // Hier holen wir uns aus einem EditText im Dialog den Wert raus und // stecken ihn in den Konstruktor des Events und feuern es mit ".post()" ab. bus.post(new ValueFromDialog(editText.getText.toString()); } }
Da zu dem Zeitpunkt wo das passiert, das Fragment im Hintergrund “am Leben ist”, kann es Events entgegen nehmen. Das Fragment muss lediglich zwei Voraussetzungen erfüllen:
# beim EventBus registriert haben – bus.register(this); – und
# eine Funktion besitzen, die die gewünschten Events abfängt und mit der Annotation@Subscribe markiert wurde!
Hier ein Beispiel für so eine Funktion.
@Subscribe public void receiveValueFromDialogEvent(final ValueFromDialogEvent inValueFromDialogEvent) { // Macht hier mit dem Event und seinme Inhalt, was immer ihr wollt. // zB. inEvent.getValue() abrufen und es dann im entsprechenden // TextView eures Fragments einfügen, da ihr ja hier nicht mehr im // Dialog seid, sondern im Fragment. }
Nun haben wir alles notwendige erledigt.
Sicherlich hört es sich initial nach viel Arbeit an, ist es aber nicht.
Zusammenfassung & Fazit:
Der Ablauf ist auf dem Papier und ohne Code, ziemlich simpel:
1.) Unser Dialog hat etwas, was an das Fragment gegeben werden soll.
2.) Dialog erzeugt ein “Event” (Klassendefinition des Events kann überall sein) und schickt es an den EventBus (“bus.post(Event)”.
3. Fragment ist beim EventBus registriert und sagt ihm: “Heeey, ich bin da!”.
4. Fragment sagt dem EventBus “Heeeey, ich nehme XYZEvent an. Schick es mir zu, wenn du ein bekommst” (@Subscribe als Annotation einer Funktion und das gewünschte Event als Parameter)
5. Fragment bekommt das Event und liest den Inhalt aus und aktualisiert die TextView!
Wie oben schon erwähnt:
Auch wenn es nach viel aussieht, sobald man das Prinzip verstanden hat, kann man enorm mächtige Sachen machen!
Natürlich ist es ein kleiner Initial-Aufwand der betrieben werden muss, aber spätestens nach dem zweiten mal wo man sich das Listener-Prinzip erspart (wie ganz oben erklärt) bei der Kommunikation zwischen Dialog -> Fragment/Activity, lohnt sich dieses Konstrukt.
Natürlich ist Otto und der EventBus nicht nur für diese Art von Kommunikation gut. Seine eigentliche Stärke, findet es in anderen Bereichen:
# Eines der tollsten Dinge die man damit machen kann, ist das Ersetzen des ach so ge- und beliebten “Loaders”. Viele Entwickler entscheiden sich immer mehr für die Methode mit den Events, gegen den Loader.
# Antworten erhalten von asynchronen Tasks
Beispiel:
ButtonClick startet einen AsyncTask. Sobald der AsyncTask beendet ist, wird ein Event verschickt über den Bus. Das Fragment/Activity in dem der Button sich befindet hat eine @Subscribe-Funktion und fängt dieses Event ab und weiß damit, sobald das Event angekommen ist, dass der AsyncTask beendet ist und ein Ergebnis da ist.
# Viele viele weitere Einsatzmöglichkeiten, wie man dieses wertvolle Werkzeug einsetzen und für seinen Vorteil nutzen kann.
Alternativen:
Neben Otto, gibt es auch weitere Möglichkeiten mit Events bzw ähnlichen Konstrukten zu arbeiten. Zu den bekanntesten Möglichkeiten gehören:
# Guava Library (Link) die neben dem EventBus noch viele viele weitere starke Features hat.
# Der LocalBroadCastManager von Android (Link)
Wenn euch eine Möglichkeit einfällt, wie und wo man Events nutzen kann, nur her damit.
Ich hoffe ich konnte euch das Prinzip hinter Otto, dem EventBus, gut erklären und es euch schmackhaft machen!
Über Kommentare und Shares, freue ich mich natürlich sehr!