I am trying to invoke a method with argument received as an argument but not able to do so. Here is what I am trying.
I have a method which gets me alert dialog object like below.
fun getAlertDialog(
title: String,
positiveButtonText: String,
positiveClickAction: (() -> Unit)) {
someTextView.setOnClickListener {
positiveClickActin.invoke()
}
and the above can be called like below
val dialog = getAlertDialog("Title", "Ok", ::clickedOk)
considering clickedOk is a void method like below
fun clickedOk() {
println("clicked")
}
But I am stuck when i want to pass a method with argument. Let's say I want to print some variable. The getSimpleDialog method can be changed as below.
fun getAlertDialog(
title: String,
positiveButtonText: String,
positiveClickAction: ((any: Any) -> Unit))
someTextView.setOnClickListener {
positiveClickActin.invoke() //this cannot be achieved now as the method takes an argument
}
and call it as
val dialog = getSimpleDialog("Hello", "ok", { variable -> println("clicked $variable")})
but i cannot invoke this method in the getSimpleDialog's on click listener. How do I achieve it?
You can either call
positiveClickActin.invoke(param)
or simply,
positiveClickActin(param)
Similarly for no parameter case you can use
positiveClickActin()
Instead of calling invoke().
While reading in the doc, the invoke() looks to be useful while having mixed of java and kotlin code. (but I might be wrong here as I am still new in kotlin)
Related
Learning Functional Programming in Kotlin, I've run into some problems in understanding
fun exampleFunction(name : String, paramFun : (String) -> Unit){
...some body code...
}
When I declare such function, as seen above, function is taking 2 parameters - String type 'name' and function type 'paramFun'.
how can paramFun, which is a function and passed as an input for exampleFunction, use name (which is parameter for exampleleFunction) as its parameter
like
fun exampleFunction(name : String, paramFun : (String) -> Unit){
paramFun(name)
}
When you call a function in a function or whatever, try to remember that the fcuntion you call (paramFun(name)), is just a copy of that same function inside exempleFunction.
So basically, when you call exampleFunction, you have 2 variable you can use inside this function, after that, when you call paramFun(name), you can use name inside as you want.
When you call a function with parameter, you can use theses parameter as many time as you want in any order you want.
Ex : This is the same thing as this.
fun functionOne(a: Int, b: Int) {
a = b //or// b = a
}
the function paramFun is the same parameter as a or b , but it's a function
I'm not entirely sure I understood your problem, because you already accomplished what you seem to have trouble with:
fun exampleFunction(name : String, paramFun : (String) -> Unit){
paramFun(name)
}
If your problem is at the call site, here is how you would call exampleFunction:
exampleFunction(name = "the name param") { someParam ->
// do what you want with someParam here
}
With this call, someParam in the lambda would get the value provided as name parameter to exampleFunction, because the body of exampleFunction actually passes name as argument to the lambda when doing paramFun(name) (just like a regular function call).
In Kotlin, I need a listener for a short piece of code which returns something, so it detects if the value returned of that code has changed. And when I mean short piece of code, I mean like calling a function that returns something. I know they have something similar this for variables:
var anyVariableNameYouWant by Delegates.observable("the value to set it to") { property, oldValue, newValue ->
Log.i(TAG, "The new value is $newValue")
}
But even if I set "the value to set it to" to the line of code, and the value returned changes, it doesn't show the log message.
So that didn't work. Does anyone know how to do this?
You could do the following to create a callback/listener. You should be able to reuse the example below.
class Event(
val onExecuted: () -> Unit
)
Then you can call it like this
fun doWork() {
val event = Event(
onExecuted = {
// This gets called later.
}
)
processEvent(event)
}
This is how you make the callback.
fun processEvent(event: Event) {
event.onExecuted()
}
Lets say I have a function fun myFunction(name:String, email:String){} and when I call this function myFunction('Ali', 'ali#test.com') how can I save this call and use it later same exactly call with same parameters?
Wrap the function call itself into a new function and save it by assigning it to a variable:
val savedFun = { myFunction("Ali", "ali#test.com") }
Then call it whenever you need it: savedFun()
Since the question came up in the comments:
How I can save multiple function calls in a list and then call them one by one?
If you don't want to pass in any parameters to your lambdas and don't care for the return value you can do something like this:
val functionList = listOf(
{ myFunction("Ali", "ali#test.com") },
{ myFunction("John", "john#doe.com") },
{ println("hello") }
)
functionList.forEach{ it() } // invoke them one by one
In case you are interested, the inferred type of functionList is List<() -> Unit>
I get to know about the Invoke operator that,
a() is equivalent to a.invoke()
Is there anything more regarding Invoke operator than please explain. Also, I did not get any example of Invoke operator overloading.
Is Invoke operator overloading possible? If possible then can anyone please explain about the Invoke operator overloading with an example? I did not get anything regarding this.
Thanks in advance.
Yes, you can overload invoke. Here's an example:
class Greeter(val greeting: String) {
operator fun invoke(target: String) = println("$greeting $target!")
}
val hello = Greeter("Hello")
hello("world") // Prints "Hello world!"
In addition to what #holi-java said, overriding invoke is useful for any class where there is a clear action, optionally taking parameters. It's also great as an extension function to Java library classes with such a method.
For example, say you have the following Java class
public class ThingParser {
public Thing parse(File file) {
// Parse the file
}
}
You can then define an extension on ThingParser from Kotlin like so:
operator fun ThingParser.invoke(file: File) = parse(file)
And use it like so
val parser = ThingParser()
val file = File("path/to/file")
val thing = parser(file) // Calls ThingParser.invoke extension function
The most way to use a invoke operator is use it as a Factory Method, for example:
// v--- call the invoke(String) operator
val data1 = Data("1")
// v--- call the invoke() operator
val default = Data()
// v-- call the constructor
val data2 = Data(2)
This is because the companion object is a special object in Kotlin. Indeed, the code Data("1") above is translated to the code as below:
val factory:Data.Companion = Data
// v-- the invoke operator is used here
val data1:Data = factory.invoke("1")
class Data(val value: Int) {
companion object {
const val DEFAULT =-1
// v--- factory method
operator fun invoke(value: String): Data = Data(value.toInt())
// v--- overloading invoke operator
operator fun invoke(): Data = Data(DEFAULT)
}
}
Operator Function invoke()
Kotlin provides an interesting function called invoke, which is an operator function. Specifying an invoke operator on a class allows it to be called on any instances of the class without a method name.
Let’s see this in action:
class Greeter(val greeting: String) {
operator fun invoke(name: String) {
println("$greeting $name")
}
}
fun main(args: Array<String>) {
val greeter = Greeter(greeting = "Welcome")
greeter(name = "Kotlin")
//this calls the invoke function which takes String as a parameter
}
A few things to note about invoke() here. It:
Is an operator function.
Can take parameters.
Can be overloaded.
Is being called on the instance of a Greeter class without method name.
In addition to the other answers:
It's possible to define a class extending an anonymous function.
class SpecialFunction : () -> Unit {}
In such case, the operator invoke is already defined, so it needs to be overriden:
class MyFunction : () -> Unit {
override fun invoke() { println("Hi Mom") }
}
One more thing about syntax repercussions:
If such "functor" is called right after constructing it, you end up with double parentheses:
MyFunction()()
And, if such functor returns another functor, you may see some obscurities like
MyFunction()()()()()...
perhaps including parameters. This will not surprise anyone coming from the JavaScript world, though.
If you have some Python background,
you can think invoke in Kotlin as __call__ in Python.
By using this, you can "call" your object as if it's a function.
One difference is: you can overload invoke, but there is no official way to overload methods in Python.
I have a Kotlin class (The problem was simplified to have a basic example), in it there is a method testedMethod() I want to test interactions on.
I want to make sure the correct parameter is passed to anotherMethod(), my problem is that the parameter is not a value but a lambda function.
A simple solution in Kotlin is what I am looking for, it may or may not be based on this solution for java.
class TestedClass {
fun testedMethod() {
anotherMethod({ passedMethod() })
}
fun passedMethod() {}
fun anotherMethod(lambdaParameter: () -> Unit) {
// Does something with lambdaParameter
}
}
This is the solution I ended up using.
Basically you create a spy of the tested class to be able to verify its own method, and you use argumentCaptor to capture the passed lambda and be able to invoke what is in it.
import com.nhaarman.mockito_kotlin.argumentCaptor
import com.nhaarman.mockito_kotlin.spy
import com.nhaarman.mockito_kotlin.verify
#Test
fun lambdaParameterPassedIsCorrect() {
val testedClass = TestedClass()
val spyOfTestedClass = spy(testedClass)
val captor = argumentCaptor<() -> Unit>()
spyOfTestedClass.testedMethod()
verify(spyOfTestedClass).anotherMethod(captor.capture())
// Invoke the function passed as a parameter
// and then verify that the expected method was called
val function = captor.firstValue
function.invoke()
verify(spyOfTestedClass).passedMethod()
}
I would still be interested in a simpler solution.
You can use mockito_kotlin library, which have the function "verify".
verify(TestedClass, times(1)).anotherMethod(eq(passedMethod))
Which verify that the method "anotherMethod" of class "TestedClass" invoked once with the parameter equal to "passedMethod"