János János - 2 months ago 13
Java Question

How to create Runnable that accept argument in Android?

In iOS I can pass a function handler to an other function, and this function handler can accept i.e. one argument, and be executed in the other method. How is it possible in Android?

public class func getImage(completion: (image: UIImage?) -> ()) {
completion(image: image)
}

Utility.getImage(completion: {image in

imageView.image = image

})


I know
Runnable
is similar to
blocks
,
closures
, but it does not accept argument. Found here an example how to pass argument to a
Runnable
, but here logic should be implemented in a separate class, and not not where 'other method' get called, so code is not as readable as in iOS way. Any idea?

Answer

In Java you need to declare interfaces a priori. You can't simply declare functional interfaces in the signature of the function that uses it. So your swift code would translate as:

// In java 7
// Declare your interface
public interface ImageListener {
    public void completed(Image image);
}

// ...
// Define your `getImage` function to use the listener
public static void getImage(ImageListener completion) {
    completion.completed(image);
}

// ...
// Call the function
Utility.getImage(new ImageListener() {
    public void completed(Image image){
        imageView.image = image;
    }
});

Or with Java 8, simply:

// Skip the interface declaration and use a predefined Java 8 Functional interface:
public static void getImage(Consumer<Image> completion) {
    completion.accept(image);
}

// ...
// Call the function
Utility.getImage(image -> imageView.image = image);

A few point to respond to Janos' comment:

  • Defining an interface allows you to have several methods, for example a method to call when an error occurs. With closures only you need as many blocks as you have methods in your interface, with an interface, a single interface is needed.
  • The interface can be anonymous, as in the examples I gave, but it can also be implemented by an object, allowing for easy reuse of the blocks, among other things.
  • In Java 8, most functional interfaces are defined already, so you don't need to define them yourself.
  • Creating an naming an interface gives it a specific meaning and purpose. It is clear what you are supposed to do with it when you receive it as a parameter.
  • There are naming conventions for interface methods that help you understand the context. For example, in Android, when an interface method starts with on, it is expected to be called on the main thread. It helps a/ the developer of the API express intent and b/ the user of the API to know what to expect. Self-documenting, if you will.

So, not a nightmare, and in many case, you don't even have to implement it if you really don't want to :)