web-dev-qa-db-fra.com

Comment envoyer un événement du service à l'activité avec le bus d'événements Otto?

Simple BusProvider.getInstance().post() amène l'exception non main thread. Comment envoyer un événement du service à l'activité avec le bus d'événements Otto?

58
Mecid

Pour publier à partir de n'importe quel fil (principal ou en arrière-plan) et recevoir sur le fil principal, essayez quelque chose comme

public class MainThreadBus extends Bus {
  private final Handler mHandler = new Handler(Looper.getMainLooper());

  @Override
  public void post(final Object event) {
    if (Looper.myLooper() == Looper.getMainLooper()) {
      super.post(event);
    } else {
      mHandler.post(new Runnable() {
        @Override
        public void run() {
          MainThreadBus.super.post(event);
        }
      });
    }
  }
}

Remarque: le mérite revient à Jake Wharton et "pommedeterresaute" à https://github.com/square/otto/issues/38 pour l'approche générale. Je viens de l'implémenter avec une classe wrapper plutôt qu'une sous-classe.

121
Andy Dennie

Pour publier à partir de n'importe quel fil (principal ou arrière-plan) et recevoir sur le fil principal, utilisez le MainThreadBus suivant au lieu d'un Vanilla Bus

public class MainThreadBus extends Bus {
     private final Handler handler = new Handler(Looper.getMainLooper());

     @Override public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    MainThreadBus.super.post(event);
                }
            });
        }
    }
}

Ceci est basé sur la réponse d'Andy Dennie.

Il n'est pas nécessaire à la fois d'étendre et d'envelopper un objet Bus, de faire l'un ou l'autre. Dans la réponse de Dennie, qui est en fait un wrapper, la classe de base Bus est simplement utilisée comme une interface, toutes les fonctionnalités sont écrasées.

Cela fonctionnerait même si vous supprimiez la classe de base Bus sauf si vous aviez justement référencé la MainThreadBus via une référence Bus.

20
alexbirkett

Ou faites-le simplement si vous êtes sûr de publier à partir d'un fil non principal:

new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        mBus.post(new myEvent());
                    }
                });

Tout comme le dit le proverbe, "Keep It Simple and Stupid" :)

3
Jiyeh

bus = nouveau bus (ThreadEnforcer.ANY); est la solution claire à ce problème. C'est tout ce que vous avez à faire.

2
drlobo

Je l'ai fait simplement:

Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                bus.post(event);
            }

        });

Bon codage .. :)

0
Shylendra Madda

Meilleure classe de bus personnalisée pour moi

public class AndroidBus extends Bus {
    private final Handler mainThread = new Handler(Looper.getMainLooper());

    @Override
    public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            mainThread.post(() -> AndroidBus.super.post(event));
        }
    }
}
0
e.shishkin