1

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?

Community
  • 1
  • 1
János
  • 32,867
  • 38
  • 193
  • 353
  • As I highlighted code is **not readable** with own class approach. – János Sep 28 '16 at 15:04
  • `I know Runnable is similar to blocks` not really. What would be similar to blocks and closures are *Functional interfaces*. Runnable is one of them, but there are many, and you can define new ones. What you are showing in swift looks like a simple listener, which you can simply define as `public interface ImageListener { public void on(Image image); }`. Or, for genericity: `public interface MyListener { public void on(T t); }` – njzk2 Sep 28 '16 at 15:18
  • see for example those two: https://github.com/smaspe/FunctionalIterables/blob/master/src/main/java/com/smaspe/iterables/FuncIter.java#L280 – njzk2 Sep 28 '16 at 15:19
  • as a side note, what you describe is very different from the question you linked: in the linked question, it is about passing a final parameter when creating the runnable, while your question is about handling the parameter passed when invoking the runnable. – njzk2 Sep 28 '16 at 15:22

2 Answers2

3

You dont need a class to create runnable with params. Here I am sharing how I use runnable with params.

private Runnable createRunnable(final String params) {
    return new Runnable() {
        @Override
        public void run() {
            // your code to run in background
            // Use your param here
        }
    };
}

use method like this to create runnable with params. Your param will be used whenever you want in runnable. But it will be final variable. So you cant change the variable inside runnable. If you want to modify variable you just have to copy param to another variable and modify.

Sujith Niraikulathan
  • 2,111
  • 18
  • 21
1

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 :)

njzk2
  • 38,969
  • 7
  • 69
  • 107
  • @János I edited the answer with a few remarks on your comment – njzk2 Sep 28 '16 at 19:54
  • Thanks, it took me time to understand your example, but I see now only the interface file is required compare to Swift, I can get use to it. :) Important that 'logic' does not need to separate out, but can keep it in `onBindViewHolder` method. – János Sep 28 '16 at 20:09