[JAVA] Verwendung von EventBus3 und ThreadMode

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.

Wie benutzt man

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).

Definition von EventBus-Instanzen mit unterschiedlichen Bereichen

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

Vorsichtsmaßnahmen für die Angabe des HINTERGRUNDES

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 ...

Verwenden Sie den Thread-Modus ordnungsgemäß

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.

Schließlich

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

Verwendung von EventBus3 und ThreadMode
Verwendung von StringBurrer und Arrays.toString.
Wie man Gleichheit und Gleichheit benutzt (wie man Gleichheit benutzt)
Verwendung von OrientJS und OrientDB zusammen
So richten Sie kapt ein und verwenden es
Verwendung von Teilzeichenfolgen und Substratmethoden
Verwendung von @Builder und @NoArgsConstructor zusammen
Verwendung von Map
Wie benutzt man rbenv?
Verwendung mit_option
Verwendung von fields_for
Verwendung von java.util.logging
Verwendung der Karte
Verwendung von collection_select
Wie benutzt man Twitter4J
Wie benutzt man active_hash! !!
Verwendung von MapStruct
Verwendung von TreeSet
[Verwendung des Etiketts]
Wie man Identität benutzt
Wie man Hash benutzt
Verwendung von Dozer.mapper
Wie benutzt man Gradle?
Verwendung von org.immutables
Verwendung von java.util.stream.Collector
Verwendung von VisualVM
Verwendung von Map
[Ruby] Verwendung der gsub-Methode und der sub-Methode
Verwendung von Segmented Control und zu notierenden Punkten
Verwendung der Scope- und Pass-Verarbeitung (Servist)
[Java] Verwendung der Kalenderklasse und der Datumsklasse
Verwendung der Ketten-API
[Java] Verwendung von Map
Verwendung der Warteschlange mit Priorität
[Rails] Verwendung von Enum
Verwendung von Java Optional
Verwendung von JUnit (Anfänger)
Verwendung von Ruby return
[Rails] Verwendung von Enum
Verwendung von @Builder (Lombok)
Verwendung der Java-Klasse
Wie man Big Decimal benutzt
[Java] Verwendung von removeAll ()
Verwendung von String [] args
Verwendung von Rails Join
Verwendung von Java Map
Ruby: Wie man Cookies benutzt
Verwendung von abhängigen :: zerstören
Verwendung von Eclipse Debug_Shell
Verwendung von Apache POI
[Rails] Verwendung der Validierung
Verwendung von Java-Variablen
[Rails] So verwenden Sie authenticate_user!