有懂 kotlin 的么,想请教一个函数为 lambda 表达式的写法的出处。

2018-12-24 13:39:02 +08:00
 abbenyyy
viewModel.gardenPlantings.observe(viewLifecycleOwner, Observer { plantings ->
       binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
})

源码出处

这个 Observer 是什么写法呢?真搞不懂,kotlin 感觉太天马行空了,来个大神指教一下,谢谢

2755 次点击
所在节点    问与答
20 条回复
jinksw
2018-12-24 13:44:34 +08:00
只有一个函数声明的接口可以用 Lambda 代替?

类似 setOnClickListener{
view->xxx
}
abbenyyy
2018-12-24 13:45:37 +08:00
@jinksw 这个我知道,谷歌的这个为何要在前面加上 Observer 呢
Mystery0
2018-12-24 14:01:54 +08:00
Observer 是一个接口,这个接口里面只有一个函数,所以可以简写成这样
Mystery0
2018-12-24 14:02:24 +08:00
其实看一下 Observer 的定义应该就清楚了
jinksw
2018-12-24 14:06:01 +08:00
@abbenyyy 不加那个 Observer 应该也可以 只是指出类型了
abbenyyy
2018-12-24 14:11:48 +08:00
@Mystery0 那为何
```
val livePlantList = Transformations.switchMap(growZoneNumber) {
if (it == NO_GROW_ZONE) {
plantRepository.getPlants()
} else {
plantRepository.getPlantsWithGrowZoneNumber(it)
}
}
```
[源码出处]( https://github.com/googlesamples/android-sunflower/blob/a85cd9b49a924ee2ad029685225d6d071de6bd15/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/PlantListViewModel.kt#L41)
Transformations.switchMap 第二个参数也是接口,Transformations.switchMap 的最后一个 lambda 表达式参数移出括号外的方式,并不能套用在 Observer 上面,也就是
```
viewModel.gardenPlantings.observe(viewLifecycleOwner) { plantings ->
binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
}
```
这个写法并不能编译通过
abbenyyy
2018-12-24 14:14:14 +08:00
@jinksw 如同我上面说的,如果函数最后一个参数是 lambda 表达式可移出括号外,但是 Observer 如果这样写,编译并不能通过。所以我搞不懂为何有这两种方式
loshine1992
2018-12-24 14:17:33 +08:00
从这个简化的

```kotlin
viewModel.gardenPlantings.observe(viewLifecycleOwner, object : Observer {

override fun 方法名(plantings: 参数类型) {
binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
}

})
```

最简化的写法是这样

```kotlin
viewModel.gardenPlantings.observe(viewLifecycleOwner) {
binding.hasPlantings = (it!= null && it.isNotEmpty())
}
```
jinksw
2018-12-24 14:22:33 +08:00
@loshine1992 然而楼主说这样不行
🤔 到底是为啥呢 是不是最后一个参数 是泛型类 的缘故
holmesabc
2018-12-24 14:23:04 +08:00
Observer 是个 java 里面的单方法 接口。就能简写
abbenyyy
2018-12-24 14:27:47 +08:00
@loshine1992 你可以 clone 下来谷歌的 android-sunflower 项目,按照你的方式改写一下,并不能编译通过,我已经试过了
jinksw
2018-12-24 14:32:23 +08:00
loshine1992
2018-12-24 14:36:32 +08:00
@abbenyyy #2 这个情况下大概率有另外一个方法也接受一个接口的参数,

observe(viewLifecycleOwner: A 参数, observer: Observer)
observe(viewLifecycleOwner: A 参数, subscriber: Subscriber)

此时需要区分,不能直接用 lambda
jinksw
2018-12-24 14:42:20 +08:00
感觉应该是编译器的锅 我看那个 observer 方法也没有重载
abbenyyy
2018-12-24 14:54:39 +08:00
@jinksw 好像是因为 observer 方法有一个通配符泛型<? super T>,所以才需要明确泛型吧
dagger2
2018-12-24 16:56:50 +08:00
viewModel.gardenPlantings.observe 是个 java 方法,接收的参数是一个 Observer 的实现,而不是() -> Unit
pipicat
2018-12-24 17:26:10 +08:00
应该跟泛型有关系。
pipicat
2018-12-24 17:33:28 +08:00
val a = object : View.OnClickListener {
override fun onClick(v: View?) {
}
}

val b = object : Observer<Any>{
override fun onChanged(t: Any?) {
}
}

idea 提示后简化成
val a = View.OnClickListener { }

val b = Observer<Any> { }

这里 observer 不加泛型是无法单独声明的。
而 livedata 的这个方法泛型已经确定了,所以
viewModel.gardenPlantings.observe(viewLifecycleOwner, Observer { plantings ->
binding.hasPlantings = (plantings != null && plantings.isNotEmpty())
})
上的泛型没有显式的写出来。
pipicat
2018-12-24 17:45:33 +08:00
测试了一下 java8 的代码。同样的代码,java8 不用显式写 Observer,但是参数要写出来。
SoloCompany
2018-12-26 23:12:43 +08:00
java8 的 function interface 和一 kotlin,的 KFunction 并不是同一种类型,需要显式转换,所以需要显式构造 Observer 接口
java8 code 则是类型推断系统自动把 lambda 转换为推断出来的 function interface 也就是说 observer,不需要通过显式的类型转换

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/520443

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX