Is there a way to take an argument in a callable method?
You can't pass arguments to call()
because the method signature doesn't allow it but here is at least one way to work around that by
- defining an abstract class that wraps/implements
Callable
and - implementing a setter to "inject" a result into
call()
Define an abstract class:
import java.util.concurrent.Callable;
public abstract class Callback<T> implements Callable<Void> {
T result;
void setResult (T result) {
this.result = result;
}
public abstract Void call ();
}
Define the method that should fire the callback:
public void iWillFireTheCallback (Callback callback) {
// You could also specify the signature like so:
// Callback<Type of result> callback
// make some information ("the result")
// available to the callback function:
callback.setResult("Some result");
// fire the callback:
callback.call();
}
In the place where you want to call iWillFireTheCallback
:
Define the callback function (even possible inside methods):
class MyCallback extends Callback {
@Override
public Void call () {
// this is the actual callback function
// the result variable is available right away:
Log.d("Callback", "The result is: " + result);
return null;
}
}
And then call iWillFireTheCallback
while passing in the callback:
iWillFireTheCallback(new MyCallback());
You can't pass it as the argument to call()
because the method signature doesn't allow it.
However, you can pass the necessary information as a constructor argument; e.g.
public class DoPing implements Callable<String>{
private final String ipToPing;
public DoPing(String ipToPing) {
this.ipToPing = ipToPing;
}
public String call() throws SomeException {
InetAddress ipAddress = InetAddress.getByName(ipToPing);
....
}
}
(I've corrected a couple of egregious code style violations!!)
There are ways to eliminate some of the "boilerplate" coding in the above (see some of the other answers). In this case we are talking about 4 lines of code (in a ~40 line class), so I am not convinced that it is worth the effort. (But hey, it is your code.)
Alternatively, you could:
declare DoPing as an inner class (or a lambda) and have it refer to a
final ipToPing
in the enclosing scope, oradd a
setIpToPing(String ipToPing)
method.
(The last allows a DoPing
object to be reused, but the downside is that you will need to synchronize to access it thread-safely.)
Adding to Jarle's answer -- in case you create Callable
as instance of anonymous class, you can use final
field outside of anonymous class for passing data into the instance:
final int arg = 64;
executor.submit(new Callable<Integer>() {
public Integer call() throws Exception {
return arg * 2;
}
});