EventBus Auf dieser Seite wird beschrieben, wie Sie EventBus3 verwenden, wie Sie eine EventBus-Instanz mit einem anderen Bereich als EventBus.getDefault () erstellen, der nicht oft erwähnt wird, und ThreadMode, der praktisch ist, aber Aufmerksamkeit erfordert. Ich denke, Sie sollten im Folgenden lesen, warum Sie EventBus überhaupt verwenden. Verwenden des Ereignisbusses unter Android
Zuerst bin ich auch zu dem oben Gesagten gekommen, aber als ich den Inhalt gelesen habe, um ihn zu verwenden, war es die Beschreibung von EventBus2, und ich habe festgestellt, dass die Verwendung in EventBus3 anders ist, also werde ich ein Beispiel in EventBus3 schreiben. Da sich das veröffentlichte Beispiel ein wenig von dem Zweck unterschied, den ich verwenden wollte, werde ich auch beschreiben, was ich für meinen Zweck tun sollte. ** Es scheint ein weit verbreitetes Missverständnis zu bestehen, dass EventBus nur im globalen Bereich verwendet werden kann **, daher werde ich auch erwähnen, dass dies nicht der Fall ist. Außerdem kann ** ThreadMode angegeben werden, um den Ausführungsthread zu steuern, was meiner Meinung nach eine sehr praktische Funktion ist, aber ich habe festgestellt, dass es notwendig ist, vorsichtig mit seinem Verhalten umzugehen **, also habe ich den Quellcode gelesen und herausgefunden. Beschreiben Sie auch die Punkte.
Es ist einfach wie folgt zu bedienen. Selbst auf der offiziellen Seite und auf anderen Websites gibt es jedoch nur Anwendungsfälle, in denen andere Klassen Activity benachrichtigen, und ich konnte keinen Anwendungsfall finden, in dem Activity andere Klassen benachrichtigt. Daher werde ich ihn in diesem Fall schreiben.
Beschreiben Sie Folgendes in build.gradle.
build.gradle
compile 'org.greenrobot:eventbus:3.0.0'
Erstellen Sie eine Klasse für das Ereignis
MessageEvent.java
public class MessageEvent {
private int eventType
public MessageEvent(int type) {
this.eventType = type;
}
public int getEventType() {
return eventType;
}
}
Klasse, über die Sie benachrichtigt werden möchten
Subscriber.java
public class Subscriber {
@Subscribe
public void onEvent(MessageEvent event) {
// do something
}
}
Benachrichtigung senden MainActivity
MainActivity.java
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private Subscriber mSubscriber;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSubscriber = new Subscriber();
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(mSubscriber);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(mSubscriber);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Send event
EventBus.getDefault().post(new MessageEvent(item.getItemId()));
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
Der Punkt ist, die Instanz zu registrieren, über die Sie benachrichtigt werden möchten, mit "EventBus.getDefault (). Register ()". EventBus enthält intern eine Reihe registrierter Instanzen. Wenn "EventBus.getDefault (). Post ()" aufgerufen wird, wird jede der Instanzmengen zum Zeitpunkt der Veröffentlichung zu einem Argument. Wir prüfen, ob es eine Methode gibt, die dem Typ der Klasse "@ Subscribe" entspricht, und wenn es eine entsprechende Methode gibt, werden wir Sie durch Aufrufen dieser Methode benachrichtigen.
In diesem Beispiel
EventBus.getDefault().post(new MessageEvent(item.getItemId()));
Wird aufgerufen, wird die Methode, die MessageEvent als Argument verwendet, von den Methoden aufgerufen, für die "@ Subscribe" in der in EventBus registrierten Instanz definiert ist (diesmal nur mSubscriber).
Die offiziellen Seiten und Artikel, die ich gesehen habe, zeigen nur Beispiele, die die Standard-EventBus-Instanz mit "EventBus.getDefault ()" verwenden. Wenn Sie nur "EventBus.getDefault ()" verwenden, sind alle mit "register ()" registrierten Instanzen der Bereich des Post-Ziels. Dies ist einfach, widerspricht jedoch der empirischen Regel, dass der Umfang eines Objekts so eng wie möglich sein sollte, und mit zunehmender Anzahl von Klassen wird es schwierig zu wissen, welche Methode tatsächlich aufgerufen wird.
Weniger bekannt ist "EventBus.getDefault ()" nur eine praktische Methode, die eine Singleton-Instanz von EventBus zurückgibt, und der Benutzer erstellt eine andere EventBus-Instanz, indem er "new EventBus ()" ausführt. Es ist auch möglich. Da die Instanzen, die "register ()" sind, nicht von EventBus-Instanzen gemeinsam genutzt werden, sollte der Bereich für jede EventBus-Instanz von "register ()" nur bestimmten Instanzen in der generierten EventBus-Instanz festgelegt werden. Kann gemacht werden.
Ein Beispiel zum Erstellen einer EventBus-Instanz für ViewModel1 und einer EventBus-Instanz für ViewModel2 ist unten dargestellt.
DifferentScopeActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mEventBusForViewModel1 = new EventBus();
mEventBusForViewModel2 = new EventBus();
mViewModel1 = new ViewModel1();
mViewModel2 = new ViewModel2();
}
@Override
protected void onStart() {
super.onStart();
mEventBusForViewModel1.register(mViewModel1);
mEventBusForViewModel2.register(mViewModel2);
}
@Override
protected void onStop() {
super.onStop();
mEventBusForViewModel1.unregister(mViewModel1);
mEventBusForViewModel2.unregister(mViewModel2);
}
Auch in der Ankündigung, die bei DroidKaigi 2017 unten sehr beliebt war
MVVM-Architektur durch DataBinding realisiert
EventBus ist global, daher ist es schwer zu sagen, woher Benachrichtigungen kommen
Ich denke, dass dem Präsentator wahrscheinlich bewusst ist, dass es nur eine Möglichkeit gibt, es mit "EventBus.getDefault ()" zu verwenden. Ich denke, dass es keinen bekannten Weg gibt, einen neuen Event Bus zu erstellen. (Ich möchte darauf hinweisen, dass die Kritik an der obigen Ankündigung nicht klar ist. Ich habe sie als Beispiel für ein häufiges Missverständnis angeführt.)
ThreadMode Durch Angabe von ThreadMode in "@ Subscribe" können Sie festlegen, welcher Thread ausgeführt werden soll.
POSTING Wenn "@Subscribe (threadMode = ThreadMode.POSTING)" angegeben ist, wird der Thread im selben Thread wie der Thread, der ** post ausgeführt hat, unterbrochen. Daher wird kein Beitrag zurückgegeben, bis die Methode "@ Subscribe" abgeschlossen ist. ** ** ** Bitte beachten Sie, dass wenn Sie von MainThread aus posten und die Seite "@ Subscribe" eine umfangreiche Verarbeitung durchführt, dies ANR ist. Im Fall von (new Handler ()). Post sollte die Post-Aktion sofort beendet worden sein, was anders ist.
--post Seite: MainThread-> Abonnementseite: MainThread --post Seite: SubThread1-> Abonnementseite: SubThread1
MAIN Wenn Sie "@Subscribe (threadMode = ThreadMode.MAIN)" angeben, wird es immer im Hauptthread des Prozesses ausgeführt. ** Wenn die Buchungsseite auch auf MainThread ausgeführt wird, wird der Thread unterbrochen, als ob POSTING angegeben worden wäre. Daher endet der Beitrag erst, wenn die Methode "@ Subscribe" beendet ist. ** ** **
--post Seite: MainThread-> Abonnementseite: MainThread --post Seite: SubThread1-> Abonnementseite: MainThread
BACKGROUND Wenn "@Subscribe (threadMode = ThreadMode.BACKGROUND)" angegeben ist, wird die Verarbeitung von anderen Threads als MainThread ausgeführt. ** Wenn die Post-Seite nicht MainThread ist, wird der Thread unterbrochen, als ob POSTING angegeben worden wäre. Daher wird kein Beitrag zurückgegeben, bis die Methode "@ Subscribe" abgeschlossen ist. ** ** **
Wenn die Nachausführung MainThread ist,
ExecutorService service = Executors.newCachedThreadPool();
service.execute(runnable);
Die Verarbeitung ist fast die gleiche wie bei. Dadurch wird sichergestellt, dass jeder Prozess parallel ausgeführt wird (es sei denn, es wird eine sehr große Anzahl von Posts ausgeführt), sodass zwischen den Methoden "@ Subscribe" kein Block besteht.
--post Seite: MainThread-> Abonnementseite: SubThread2 oder 3 oder 4 oder ... --post Seite: SubThread1-> Abonnementseite: SubThread1
Wenn die Post-Seite MainThread ist, wird die Verarbeitung auf der Seite "@ Subscribe" nicht serialisiert (sequentiell) **. Wenn also Ressourcen innerhalb der Methode "@ Subscribe" geschützt werden müssen Muss ordnungsgemäß geschützt werden.
Um ein Beispiel zu geben
Subscriber.java
int resource = 0;
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void handleEvent() {
resource++;
}
Publisher.java
private void postManyEvents() {
for(int i=0; i<10000; i++) {
EventBus.getDefault().post();
}
}
Wenn Sie 10000 Mal in Form von posten, gibt es keine Garantie dafür, dass die Ressource des Abonnenten 10000 ist (da der ++ - Operator nicht atomar arbeitet). Verwenden Sie zur Lösung dieses Problems eine Atomklasse wie unten gezeigt oder schützen Sie sie mit einem synkronisierten Block oder ähnlichem.
Subscriber.java
AtomicInteger resource = new AtomicInteger(0);
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void handleEvent() {
resource.incrementAndGet();
}
Publisher.java
private void postManyEvents() {
for(int i=0; i<10000; i++) {
EventBus.getDefault().post();
}
}
ASYNC Wenn "@Subscribe (threadMode = ThreadMode.ASYNC)" angegeben ist, wird der Prozess immer im Hintergrundthread ausgeführt, unabhängig davon, um welchen Beitrag es sich handelt. Dies ist das gleiche Verhalten wie in der HINTERGRUND-Spezifikation, wenn die Pfostenseite Hauptgewinde ist. Mit anderen Worten, es sind dieselben Vorsichtsmaßnahmen erforderlich wie bei der Angabe von HINTERGRUND.
--post Seite: MainThread-> Abonnementseite: SubThread2 oder 3 oder 4 oder ... --post Seite: SubThread1-> Abonnementseite: SubThread2 oder 3 oder 4 oder ...
Es ist besser, nicht so viel wie möglich in MainThread zu verarbeiten, aber es ist schwierig, sie ordnungsgemäß zu verwenden, da Dateninkonsistenzen oder -ausnahmen an unerwarteten Stellen auftreten, wenn es sich um separate Threads handelt. Ich denke, dass die Verwendung von nur zwei, MainThread und WorkerThread, das beste Gleichgewicht zwischen Sicherheit und Reaktion darstellt. Daher ist die Richtlinie zum Festlegen von POSTING und zum Auslösen der Verarbeitung in WorkerThread in der Methode am besten. Es kann sicher sein. Wenn es einen Prozess gibt, der in MainThread auf der Seite "@ Subscribe" ausgeführt werden muss, muss MAIN angegeben werden. Ich denke auch, dass es besser ist, ASYNC für die Verarbeitung anzugeben, die keine Probleme verursacht, selbst wenn sie parallel arbeitet.
Beschrieben EventBus3, um Android-Code aus der Callback-Hölle zu befreien. Bitte beachten Sie, dass ThreadMode unerwartet nicht intuitiv ist.
Wenn Sie "@ WorkerThread" oder ähnliches angeben, scheint es einfacher zu sein, es persönlich zu verwenden, wenn Sie in Serie mit einem einzelnen SubThread arbeiten. Machen wir es also selbst.
Recommended Posts