bennidi / mbassador

Powerful event-bus optimized for high throughput in multi-threaded applications. Features: Sync and Async event publication, weak/strong references, event filtering, annotation driven
MIT License
955 stars 146 forks source link

Configure invokation thread #89

Closed potmo closed 9 years ago

potmo commented 9 years ago

Is it possible to configure the thread that the handlers are invoked on? When using MBassador on Android it would be nice to be able to run all the invocations on the UIThread so that doesn't have to be handled in the handler. I tried to configure the AsynchronousHandlerInvocation feature and replace the ThreadFactory with my own that ran on the UI thread. The problem is that the threads are also taking pending messages in the anonymous inner class of initDispatcherThreads. That means that the UIThread is blocked.

It would be nice to be able to be able to configure this block:

 try {
  publication = pendingMessages.take();
  publication.execute();    <------ I want to do this on a separate UIThread
} catch (InterruptedException e) {
  Thread.currentThread().interrupt();
  return;
} catch(Throwable t){
  handlePublicationError(new PublicationError(t, "Error in asynchronous dispatch",publication));
}
bennidi commented 9 years ago

Have a look at the surrounding code. You will see that the Thread is created by a ThreadFactory that is part of the feature used to configure the asynchronous message dispatch. You can replace the default factory with something else.

potmo commented 9 years ago

yes but Id like to execute pendingMessages.take() and publication.execute() on two different threads. take() is blocking so I can't run that on the ui-thread. I only want to run execute() on the ui-thread. I could have overridden the entire function but then pendingMessages is private so I haven't got access in my subclass to that.

bennidi commented 9 years ago

I'm sorry but I don't understand your requirement.

When using MBassador on Android it would be nice to be able to run all the invocations on the UIThread so that doesn't have to be handled in the handler.

What do you mean by "handled in the handler". And why would you want to run the invocations in the UI thread if you can actually have a different thread to take care of that?

potmo commented 9 years ago

Oh sorry for the bad description.

Say that you have an Android Activity with function annotated with @Handler. When MBassador calls the annotated method it will run in an MBassador invoker thread (in the asynchronous case). On Android you can only modify graphical elements if you do it from a special UIThread that Android provides. That means that every time I handle a callback from MBassador I need to manually switch to the UIThread (with the built in Activity.runOnUIThread(runnable) ). The thing is that I want to modify the UI on all the callbacks so i'd like to centralize that switch to the UIThread somewhere with MBassador instead of manually call runOnUIThread in all methods annotated with @Handler.

potmo commented 9 years ago
// This is what I have to do now
  @Handler
  public void handle(final SomeData data) {
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
        handleTheDataNowOnTheUiThread(data);
      }
    });
  }
bennidi commented 9 years ago

Ok, I do understand now. I think that a simple solution would be to move this boilerplate code up to a common base class. If this is not possible because of class hierarchy constraints (extending Android UI components), then a custom HandlerInvocation would do the trick. Simply place the code of your example in the handler invocation. You could then define an alias annotation like @HandleInUI that uses this invocation by default.

Have a look at CustomHandlerAnnotationTest to see how it is done.

potmo commented 9 years ago

Thanks i'll have a look