Goro 2.0

June 11, 2014

A few months ago I wrote about Goro library which we use to organize asynchronous tasks execution in named queues. And today we announce a new version that brings a few nice features. They are all listed in our change log. Here I would like to highlight my favourites.

Simplified Service Interaction

As a rule we use Goro instance within a Service context. This is motivated by our intent to let Android system know about tasks execution and ensure that our application process is not the first candidate for killing after our Activities are sent to the background. Hence, we have two variants of scheduling our tasks:

  1. Bind to a service, obtain Goro instance, and use its schedule method;
  2. Make our task implement Parcelable interface, put it inside of Intent, and schedule with context.startService(taskIntent).

GoroService implementation available from the first version makes these two variants possible and ensures that the service lives until all scheduled tasks are finished and all clients are unbound. In a previous post both cases were illustrated with examples. As you can see using Goro though a Service brings some complexity compared to simple

Goro goro = Goro.create(); // make it a singleton
goro.schedule("log-file-queue", new WriteToLog("start"));

And since this is the main scenario in terms of how we use Goro, the new version addresses this complexity by introducing a new class, BoundGoro, that brings three new methods: bind, unbind, and bindOneshot. Let’s look at an example.

public class MyActivity extends Activity {
  private final BoundGoro goro = Goro.bindWith(this);

  protected void onCreate(Bundle savedInstanceState) {
    // ...
    someButton.setOnClickListener(new OnClickListener() {
      public void onClick(View view) {
        goro.schedule(new SendRequestTask());
  protected void onStart() {

  protected void onStop() {

Not that hard really. And what you get is binding to GoroService when the activity starts, unbinding when it finishes, and a Goro instance that can be used to enqueu tasks execution behind the service very easily. It’s your decision as to when the activity should bind to the service: you may move bind/unbind methods invocation to onCreate/onDestroy or onResume/onPause depending on your needs.

Note that in the example above a task enqueued with goro.schedule invoked after Activity goes to background (after onStop is called) will not be executed until onStart method is called again.

To get a BoundGoro instance we supply the activity as a context used to invoke context.bindService.

Keep in mind that you shouldn’t create multiple BoundGoro instances for the same Context. Thus, do not create it in fragments. Instead you should get Goro from an activity owning your fragment. For example

// somewhere in a fragment
Goro goro = ((MyActivity) getActivity()).getGoro();

Let’s illustrate how this can be done with Dagger.

@Module(injects = MyFragment.class)
final class MyActivityModule {
 private final MyActivity activity;
 @Provides Goro provideGoro() { return activity.goro; }
public class MyActivity extends Activity {
 final BoundGoro goro = Goro.bindWith(this);
 private ObjectGraph graph;
 protected void onCreate(Bundle savedInstanceState) {
   graph = ObjectGraph.create(new MyActivityModule(this));
 // onStart, onStop skipped
 void inject(Object target) {
public class MyFragment extends Fragments {
 @Inject Goro goro;
 public void onCreate(Bundle savedInstanceState) {
   ((MyActivity) getActivity()).inject(this);

You may easily use BoundGoro in your Services calling bind() in onCreate and unbind() in onDestroy().

The BoundGoro class also has one more method named bindOneshot. Calling this method you instruct Goro to unbind from the service as soon as all the tasks are delegated to the service after service connection is established; unbind cannot be called after bindOneshot. We strongly encourage you to use this approach in your Application class only.

public class MyApplication extends Application {
  @Override public void onCreate() {
    BoundGoro goro = Goro.bindWith(this);
    goro.schedule(new InitTask())
      .subscribe(new FutureObserver() {
        @Override public void onSuccess(Boolean ok) { 
          if (ok) Log.i(“app”, “Init completed”); 
        @Override public void onError(Throwable error) { 
          throw new AssertionError(error); 

From Receivers you cannot bind to a service. Hence, you cannot use BoundGoro there (no, we do not have support for peekService). Thus the only way is to pack tasks into an Intent and enqueue them with startService. Note that this approach can be very useful when you want some task to be executed on notification click or when you want to schedule it with Android’s AlarmManager.

// SimpleTask implements Parcelable
Intent taskIntent =
    GoroService.taskIntent(context, new SimpleTask("Hello!"));
PendingIntent operation =
    PendingIntent.getService(context, 0, taskIntent, 0);
// Schedule with AlarmManager
    AlarmManager.ELAPSED_REALTIME, time, operation
// set as notification action
new Notification.Builder(context)
// or enqueue it now

Observable Futures

Since the 2.0 version Goro’s schedule method returns an extended Future interface: ObservableFuture. It allows you to invoke subscribe method and pass an execution listener that can handle results and errors. You can see its usage in an Application class example above. This feature also allows you to easily add RxJava support to Goro library. Now you can get rx.Observable as a result of schedule method invocation on RxGoro object from the support package.

RxGoro rxGoro = new RxGoro(goro);
Observable<String> observable = rxGoro
    .schedule(new ReturnStringTask());

Actually the support package contains one more class with the name ‘AsyncGoro’. It integrates Goro with yet another library that will be described in a future post ☺. Meanwhile you can take a look at an example of Activity which downloads tweets using this class.

Error Handling Notes

We strongly encourage you to read these notes about handling errors with Goro. One thing to keep in mind is that your app will crash by default if an exception is thrown by a task enqueued via startService call. In case of operating on Goro directly and invoking schedule, it’s your responsibility to process thrown exceptions. If you do not process them in any way, they will go silently.

Future Plans

For our current tasks scheduling background operations can be done easily with Goro. However, you should be careful implementing Callables that are scheduled and avoid keeping references to activities in them. Thus it’s not recommended to pass anonymous class instances created inside activities or fragments to Goro. Hence, we want to make special Lint rules that will help to resolve such potential problems. Also we plan a Lint rule that looks for bindOneshot invocations outside the Application context.

And of course spreading Goro application field may introduce new features like priorities to control queues.

Happy queuing!