【问题标题】:How to send event from Service to Activity with Otto event bus?如何使用 Otto 事件总线将事件从服务发送到活动?
【发布时间】:2013-03-15 11:53:31
【问题描述】:

简单的BusProvider.getInstance().post() 带来异常而不是main thread。 如何使用 Otto 事件总线将事件从 Service 发送到 Activity?

【问题讨论】:

  • 默认情况下 Otto 使用 MAIN 线程(请参阅线程执行:square.github.com/otto)。你想从另一个线程发帖吗?包括示例代码和您的堆栈跟踪。
  • 实现此目的的另一种方法是使用runOnUiThread,前提是可以访问活动。不是很干净,但可以胜任。

标签: android otto


【解决方案1】:

要从任何线程(主线程或后台)发帖并在主线程上接收,请尝试类似

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);
        }
      });
    }
  }
}

注意:一般方法要归功于 Jake Wharton 和 https://github.com/square/otto/issues/38 的“pommedeterresaute”。我只是用包装类而不是子类来实现它。

【讨论】:

  • 谢谢。那么到目前为止,Bus bus2 = new Bus(ThreadEnforcer.MAIN); 解决了吗?
  • 对我来说ThreadEnforcer.MAIN 没有解决它,但是这里提供的代码。
  • @platzhirsch 来自文档:如果您不关心正在发生哪个线程交互,请使用 ThreadEnforcer.ANY 实例化一个总线实例
  • @gdrc 感谢您了解这一点。在查看源代码后,它变得清晰了。我以为ThreadEnforcer.ANY 是默认值。
  • 为什么要使用包装器和子类?非常混乱。
【解决方案2】:

要从任何线程(主线程或后台)发帖并在主线程上接收,请使用以下MainThreadBus 而不是原版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);
                }
            });
        }
    }
}

这是基于安迪丹尼的回答。

没有必要同时扩展和包装Bus 对象,做一个或另一个。在 Dennie 的回答中,它实际上是一个包装器,Bus 基类只是像接口一样被使用,所有功能都被覆盖了。

即使您删除了Bus 基类,它也可以工作,除非您碰巧通过Bus 引用引用了MainThreadBus

【讨论】:

  • 我的答案实现了一个接口,该接口当时是 Otto 的一部分,但后来被删除(有人编辑了我的答案以使其扩展而不是实现);这就是为什么它现在看起来很奇怪。在我的示例中,我想包装另一个不限于仅在主线程上使用的总线。
【解决方案3】:

如果你确定你是从非主线程发帖的,或者干脆这样做:

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

【讨论】:

    【解决方案4】:

    bus = new Bus(ThreadEnforcer.ANY);是这个问题的明确解决方案。 这就是你所要做的。

    【讨论】:

      【解决方案5】:

      对我来说最好的实现自定义总线类

      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));
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        我做的很简单:

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

        【讨论】:

          【解决方案7】:

          只需使用ThreadEnforcer.NONE 创建BasicBus 即可从非主线程发布事件。提到的ThreadEnforcer.MAIN 正好相反(也是默认值),它只接受来自主线程的帖子。

          【讨论】:

          • 这不太可能是一个可用的答案。 OP 说“... to Activity ...”,这对我来说意味着需要在 UI 或主线程上完成处理。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多