Completion handlers in Java?
Asked Answered
T

2

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.

Toombs answered 27/2, 2014 at 19:2 Comment(0)
M
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.)

Malvoisie answered 27/2, 2014 at 19:16 Comment(4)
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?Toombs
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());.Malvoisie
I recommend declaring the interface inside the class and making it public, so it is clear that the completion handler belongs to the class.Silverstein
I'm getting the following error: Cannot resolve method 'setCompletionHandler(anonymous com.mypackage.CompletionHandler)'. Could anyone please help?Thornhill
B
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...

Blanton answered 27/2, 2014 at 19:8 Comment(3)
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?Toombs
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 <interface name>(){} and it should either drop the methods in or give you the option to add the methods.Blanton
@Blanton How did you do it in the end? Any simple sample codes pleaseSemasiology

© 2022 - 2024 — McMap. All rights reserved.