问题
I have an interface in my Adapter class:
interface OnItemClickListener {
fun onItemClick(view: View)
}
TAKE NOTE that my interface is in Kotlin.
which I want to set via this method:
public fun setItemClickListener(itemClickListener: OnItemClickListener) {
this.onItemClickListener = itemClickListener
}
How do I use the setItemClickListener method in my Fragment class like what I used to do in Java? i.e.
adapter.setItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(View view) {
// do something
}
}
I know that I can use an onItemTouchListener but I am still new to Kotlin and I'm trying to learn some techniques like Lambdas and such.
回答1:
The problem is that your interface is defined in Kotlin (since it has fun). Lambdas can only be used for Java interfaces:
Also note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.
So in Kotlin you are supposed to use
public fun setItemClickListener(itemClickListener: (View) -> Unit)
instead of defining OnItemClickListener. You could also create a factory method:
// in Adapter's companion object
public inline fun OnItemClickListener(body: (View) -> Unit) = object : OnItemClickListener {
override fun onItemClick(view: View) { body(view) }
}
and then
adapter.setItemClickListener(Adapter.OnItemClickListener { view -> ... })
回答2:
Without lambda you can do it like this
adapter.setItemClickListener(object :View.OnItemClickListener{
override fun onItemClick(p0: View?) {
}
})
回答3:
This is how we do it in lambda
adapter.setItemClickListener{ Log.i("Adapter", "onItemClick event fired on " + it.id) }
Here it is the instance of View which is the parameter of onItemClick method.
More information on it is here https://kotlinlang.org/docs/reference/lambdas.html#it-implicit-name-of-a-single-parameter
You can find more information in Kotlin docs here https://kotlinlang.org/docs/reference/lambdas.html#lambda-expressions-and-anonymous-functions
回答4:
If you want to assign interface with single method, you can just write this:
adapter.setItemClickListener { view ->
/* some code here */
}
Or even better:
adapter.setItemClickListener {
/* some code here, to use "view" use keyword "it" */
}
If you want look deeper, let's analize signature of your method:
public fun setItemClickListener(itemClickListener: OnItemClickListener)
this is actually equals to
public fun setItemClickListener(singleMethodListener: (View) -> Unit)
If your last argument is function, you can just forget about '()', and pass lambda. One more example:
public fun setItemClickListener(parameter: Int, singleMethodListener: (View) -> Unit)
to call method above, your code should be:
item.setItemClickListener(0) { /* lambda here */ }
The problem is when you have interface with more than one method, because then you cannot pass lambda :(
Example:
interface OnItemClickListener {
fun onItemClick(view: View)
fun onDoubleItemClick(view: View)
}
Then, you cannot pass sample labda, because you have to define 2 methods. Then, you have to do the same thing like in java, but in other syntax:
adapter.setItemClickListener(object : OnItemClickListener {
/* method declarations here, like in java */
})
I hope I have explained base-lambda syntax in Kotlin :D Any question? Ask ;)
来源:https://stackoverflow.com/questions/50921677/setting-anonymous-interface-in-kotlin