|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "EventBus" |
| 4 | +date: 2019-06-03 |
| 5 | +categories: ["Biblioteki"] |
| 6 | +image: libraries/eventbus |
| 7 | +github: libraries/tree/master/eventbus |
| 8 | +description: "Biblioteki" |
| 9 | +version: EventBus 3.1 |
| 10 | +keywords: "eventbus, szyna zdarzeń, zdarzenie, obserwator, obserwowany, observer, observable, subscribe, thread, java, android, programowanie, programming" |
| 11 | +--- |
| 12 | + |
| 13 | +## Szyna zdarzeń |
| 14 | +Szyna zdarzeń `EventBus` upraszcza komunikacje pomiędzy różnymi komponentami systemu `Android` (`Activity`, `Fragment`, `Service` itp) za pomocą zdarzeń (`event`) co szczególnie może być przydatne w zadaniach asynchronicznych. Jest realizacją wzorca `Obserwator` (`Observer`) - wprowadza podział na nadawców oraz odbiorców. Zdarzenie emitowane jest przez jednego nadawcę i trafia do wszystkich aktywnych odbiorców zarejestrowanych do szyny zdarzeń. Dobrze radzi sobie z cyklem życia komponentów oraz wątkami tła, posiada lekką strukturę, unika złożonych zależności i upraszcza kod. Jednakże z momentem wprowadzenia, stabilizacji i zyskiwania popularności programowania reaktywnego w `RxJava`, architektura szyny zdarzeń staje się przestarzała. Oba projekty implementują ten sam model programowania oparty o zdarzenia lecz `RxJava` jest bardziej wydajne i zapewnia lepszą kontrolę nad wątkami przez co wydaje się naturalnym następnikiem. Konfiguracja i zmiana domyślnego zachowania instancji `EventBus` powinna zostać przeprowadzona przed pierwszym użyciem instancji szyny zdarzeń. |
| 15 | + |
| 16 | +{% highlight kotlin %} |
| 17 | +class App : Application() { |
| 18 | + |
| 19 | + override fun onCreate() { |
| 20 | + super.onCreate() |
| 21 | + //customize default EventBus instance must be called before first subscriber called |
| 22 | + EventBus.builder() |
| 23 | + .logNoSubscriberMessages(false) //do not log when no subscriber exists |
| 24 | + .sendNoSubscriberEvent(false) //do not send SubscriberEvent if no subscriber exists |
| 25 | + .throwSubscriberException(BuildConfig.DEBUG) //throw exceptions only in debug mode |
| 26 | + .installDefaultEventBus() |
| 27 | + |
| 28 | + //or create custom instance by using build method |
| 29 | + } |
| 30 | +} |
| 31 | +{% endhighlight %} |
| 32 | + |
| 33 | +## Rejestracja |
| 34 | +Aby móc odbierać zdarzenia zarówno subskrybenci powinni dokonać rejestracji do instancji szyny zdarzeń EventBus zgodnie ze swoim cyklem życia. Należy również pamiętać o prawidłowym odrejestrowaniu komponentów co w przeciwnym razie może prowadzić do wycieku pamięci. |
| 35 | + |
| 36 | +{% highlight kotlin %} |
| 37 | +//some Android component class |
| 38 | +class MainActivity : AppCompatActivity() { |
| 39 | + |
| 40 | + override fun onCreate(savedInstanceState: Bundle?) { |
| 41 | + super.onCreate(savedInstanceState) |
| 42 | + setContentView(R.layout.activity_main) |
| 43 | + } |
| 44 | + |
| 45 | + //register in proper place of lifecycle |
| 46 | + public override fun onStart() { |
| 47 | + super.onStart() |
| 48 | + EventBus.getDefault().register(this) |
| 49 | + } |
| 50 | + |
| 51 | + //unregister to avoid leak memory |
| 52 | + public override fun onStop() { |
| 53 | + super.onStop() |
| 54 | + EventBus.getDefault().unregister(this) |
| 55 | + } |
| 56 | +} |
| 57 | +{% endhighlight %} |
| 58 | + |
| 59 | +## Zdarzenie |
| 60 | +Zdarzenie jest niczym innym jak emisją obiektu danej klasy przez nadawcę. W sytuacji, gdy pożądane jest rozróżnienie zdarzeń o tej samej strukturze należy stworzyć dla każdego rodzaju zdarzenia klasę opakowującą (`wrapper`). Dobrą praktyką jest zawieranie w nazwie klasy słowa `Event`. |
| 61 | + |
| 62 | +{% highlight kotlin %} |
| 63 | +data class MessageEvent(val number: Int, val text: String) { |
| 64 | + //more fields |
| 65 | +} |
| 66 | + |
| 67 | +//if want emit some primitive type create class wrapper |
| 68 | +//Custom1Event and Custom2Event have the same properties but are different events |
| 69 | +class Custom1Event(val message: String) { |
| 70 | +} |
| 71 | + |
| 72 | +class Custom2Event(val name: String) { |
| 73 | +} |
| 74 | +{% endhighlight %} |
| 75 | + |
| 76 | +## Nadawca |
| 77 | +Wysyłania zdarzenia zachodzi na instancji `EventBus` z dowolnego fragmentu kodu i przeprowadzane jest przez przekazywanie obiektu do metody `post` lub `postSticky` (dla zdarzenia, które ma zostać zapamiętane do przyszłego użycia). |
| 78 | + |
| 79 | +{% highlight kotlin %} |
| 80 | +EventBus.getDefault().post(MessageEvent(100, "text")) |
| 81 | +EventBus.getDefault().postSticky(Custom2Event("Johnnie")) |
| 82 | +{% endhighlight %} |
| 83 | + |
| 84 | +## Subskrybent |
| 85 | +Aby zarejestrowany komponent mógł reagować na emisję danego zdarzenia powinien implementować metodę oznaczoną adnotacją `@Subscribe` i przyjmującą jako parametr wybrany typ (nazwa metody nie ma znaczenia). Dodatkowo istnieje możliwość ustawienia wątku roboczego na jakim odebrane zdarzenie będzie wykonywało pracę (`threadMode`), ustalenie priorytetu subskrypcji w obrębie tego samego wątku (`priority`) czy zdecydowanie o pobieraniu ostatniej znanej instancji zdarzenia (`sticky`). Każdy subskrybent zostanie wywołane dokładnie raz. |
| 86 | + |
| 87 | +{% highlight kotlin %} |
| 88 | +//choose one of POSTING, MAIN, BACKGROUND, MAIN_ORDERED, ASYNC |
| 89 | +@Subscribe(threadMode = ThreadMode.MAIN) //ThreadMode.POSTING is by default |
| 90 | +fun onMessageEvent(event: MessageEvent) { |
| 91 | + //do something with received event on the main UI thread |
| 92 | +} |
| 93 | + |
| 94 | +//priority 0 is default |
| 95 | +@Subscribe |
| 96 | +fun onMessageEvent(event: Custom1Event) { |
| 97 | + //do something with received event on the background thread |
| 98 | + |
| 99 | + //on some conditions |
| 100 | + //prevent delivery to other subscribers with lower priority |
| 101 | + EventBus.getDefault().cancelEventDelivery(event) |
| 102 | +} |
| 103 | + |
| 104 | +@Subscribe(priority = 1) |
| 105 | +fun onMessageEventExtra(event: Custom1Event) { |
| 106 | + //do something with received event on the background thread |
| 107 | +} |
| 108 | + |
| 109 | +//received value only from events posted by postSticky |
| 110 | +@Subscribe(sticky = true) |
| 111 | +fun onMessageEvent(event: Custom2Event) { |
| 112 | + //receive previously posted sticky event immediately |
| 113 | + //listen for new event |
| 114 | +} |
| 115 | +{% endhighlight %} |
0 commit comments