17

I've been coding for iOS and I'm quite familiar with the concept of blocks in Objective-C. Now I'm leaning Java for Android and trying to convert some apps from Android to iOS.

I read that there no perfect equivalent of blocks in Java, so I'd like to know what is the best alternative to implement completion handlers or anything that could work similarly.

Guilherme
  • 7,839
  • 9
  • 56
  • 99

2 Answers2

28

Interface types, in general. You can use Runnable (which is an interface) as Rob suggested if your handler has no parameters and a void return type. But it's simple enough to define your own:

interface CompletionHandler {
    public void handle(String reason);
}

and then to pass it to your own class:

something.setCompletionHandler(new CompletionHandler() {
    @Override
    public void handle(String reason) {
        ...
    }
});

In the other class:

void setCompletionHandler(CompletionHandler h) {
     savedHandler = h;
}

and then call it just by calling the method:

savedHandler.handle("Some mysterious reason");

This sort of thing is done for "listeners" in Java Swing and Android libraries all over the place; see View.OnClickListener, for example.

(P.S. I believe that Java 8 lambdas will be usable with all of these interface examples.)

ajb
  • 31,309
  • 3
  • 58
  • 84
  • Indeed, I will need some parameters. Is it possible to declare the `CompletionHandler` interface just once and then overload the `handle` method when I override it? – Guilherme Feb 27 '14 at 19:25
  • You *would* declare `CompletionHandler` just once, and yes, you can use the same syntax multiple times with different code for `handle`. Note that every time you do so, you're actually declaring a new class that `implements CompletionHandler`, but it's an anonymous class. If you want to use the same `handle` body multiple times, you can also declare a named class that implements it, and you can create a new instance of it with `new`, e.g. `setCompletionHandler(new CommonCompletionHandler());`. – ajb Feb 27 '14 at 19:29
  • I recommend declaring the `interface` inside the `class` and making it `public`, so it is clear that the completion handler belongs to the class. – Manuel Dec 16 '18 at 14:52
  • I'm getting the following error: Cannot resolve method 'setCompletionHandler(anonymous com.mypackage.CompletionHandler)'. Could anyone please help? – Arjun Nov 30 '20 at 04:22
4

You can do runnables. Obviously, the equivalent of blocks is going to require lambdas which are coming in Java 8, but who knows how long before Android supports them (they are still using JUnit 3.8).

There are a LOT of places in Android where things are done that are like blocks, for instance:

  this.currentConditionsActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            currentConditionsActivity.onLocationChanged(...);
        }
    });
    instrumentation.waitForIdleSync();
    setupViewElements();

As you can see, you have to make an instance of an anonymous class, but in most IDEs, the stupidity of the boilerplate is eased by autofilling. This was done in Android Studio and it put the whole thing in after doing new Runnable() (and if you fold the code, it even shows syntax similar to what lambdas will have).

So that's the state for now. Not as bad many make it seem...

Rob
  • 11,446
  • 7
  • 39
  • 57
  • Thanks, that looks like exactly what I needed. Just another quick question, how exactly is the method declared, and how do I invoke the handler? – Guilherme Feb 27 '14 at 19:13
  • All runnables have a method run which is why Android Studio can just throw it in there for you. You can define your own anonymous classes too, just declare an interface then do new (){} and it should either drop the methods in or give you the option to add the methods. – Rob Feb 27 '14 at 19:29
  • @Rob How did you do it in the end? Any simple sample codes please – JayVDiyk Dec 16 '15 at 09:02