obj.apply{ func1() } 的结果不同于 obj.func1()
Result of obj.apply{ func1() } is different than obj.func1()
在kotlin中,apply{}
定义为inline fun <T> T.apply(block: T.() -> Unit): T
我以为使用这个函数是为了最小化这段代码
obj.func1()
obj.func2()
obj.func3()
...
至
obj.apply {
func1()
func2()
func3()
}
但现在我认为它有一些完全不同的实际用例。在我的 android 工作室项目中,我得到了这个日志
2020-12-08 13:3:22.648 28006-28006/com.skb.skara D/VideoViewActivity: onStart: pos 2677
2020-12-08 13:3:22.649 28006-28006/com.skb.skara D/VideoViewActivity: initializePlayer: seeked to 0
2020-12-08 13:3:22.650 28006-28006/com.skb.skara D/VideoViewActivity: onStart: pos 2677
对于此代码
private var currentPosition: Int
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart: pos $currentPosition")
initializePlayer()
Log.d(TAG, "onStart: pos $currentPosition")
if (currentPosition == 0) {
Log.d(TAG, "onStart: vid start")
fullscreen_video.start()
}
show()
}
private fun initializePlayer() {
fullscreen_video.apply {
setVideoPath(videoUrl)
seekTo(currentPosition)
Log.d(TAG, "initializePlayer: seeked to $currentPosition")
}
}
然后我把initialisePlayer
函数改成了这个
private fun initializePlayer() {
fullscreen_video.setVideoPath(videoUrl)
fullscreen_video.seekTo(currentPosition)
Log.d(TAG, "initializePlayer: seeked to $currentPosition")
}
然后我得到了这个日志
2020-12-08 13:12:53.548 28006-28006/com.skb.skara D/VideoViewActivity: onStart: 2677
2020-12-08 13:12:53.550 28006-28006/com.skb.skara D/VideoViewActivity: initializePlayer: seeked to 2677
2020-12-08 13:12:53.550 28006-28006/com.skb.skara D/VideoViewActivity: onStart: 2677
有人请解释这个行为并解释作用域函数的使用apply{}
看下面的table,范围内也是,this.currentPosition
是fullscreen_video.currentPosition
,而不是你的var currentPosition
Kotlin 的作用域运算符就像一把瑞士军刀,每个场景都有一个方法。
https://kotlinlang.org/docs/reference/scope-functions.html
Function
Object reference
Return value
Is extension function
let
it
Lambda result
Yes
run
this
Lambda result
Yes
run
-
Lambda result
No: called without the context object
with
this
Lambda result
No: takes the context object as an argument.
apply
this
Context object
Yes
also
it
Context object
Yes
它对于 DSL API 以及在创建一个简单的 Java 对象后调用多个 setter 非常有用。
val x = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
init(null as KeyStore?)
}
在这种形式中,不完整的对象在完全构造之前永远不可用。所以可以直接赋值给一个字段(忽略并发和内存壁垒)。
而且还保持表达式形式的内容,因此您可以链接运算符,而不是强制改变值。
这是一个示例,其中 also
很有用。
fun getRandomInt(): Int {
return Random.nextInt(100).also {
writeToLog("getRandomInt() generated value $it")
}
}
如果您切换到 also,它应该会更清楚地说明您的情况。
小心,VideoView
有自己的currentPosition。在其 apply
块内访问 currentPosition
将获得 VideoView
.
的 currentPosition
private fun initializePlayer() {
fullscreen_video.apply {
setVideoPath(videoUrl)
seekTo(currentPosition) // This will use VideoView.currentPosition
Log.d(TAG, "initializePlayer: seeked to $currentPosition") // This, too
}
}
关于apply
的解释:
The context object is available as a receiver (this
). And this
always can be omitted.
如果要访问上面声明的 currentPosition
,请使用 this@YourActivity.currentPosition
。将 YourActivity
替换为您的 activity.
在kotlin中,apply{}
定义为inline fun <T> T.apply(block: T.() -> Unit): T
我以为使用这个函数是为了最小化这段代码
obj.func1()
obj.func2()
obj.func3()
...
至
obj.apply {
func1()
func2()
func3()
}
但现在我认为它有一些完全不同的实际用例。在我的 android 工作室项目中,我得到了这个日志
2020-12-08 13:3:22.648 28006-28006/com.skb.skara D/VideoViewActivity: onStart: pos 2677
2020-12-08 13:3:22.649 28006-28006/com.skb.skara D/VideoViewActivity: initializePlayer: seeked to 0
2020-12-08 13:3:22.650 28006-28006/com.skb.skara D/VideoViewActivity: onStart: pos 2677
对于此代码
private var currentPosition: Int
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart: pos $currentPosition")
initializePlayer()
Log.d(TAG, "onStart: pos $currentPosition")
if (currentPosition == 0) {
Log.d(TAG, "onStart: vid start")
fullscreen_video.start()
}
show()
}
private fun initializePlayer() {
fullscreen_video.apply {
setVideoPath(videoUrl)
seekTo(currentPosition)
Log.d(TAG, "initializePlayer: seeked to $currentPosition")
}
}
然后我把initialisePlayer
函数改成了这个
private fun initializePlayer() {
fullscreen_video.setVideoPath(videoUrl)
fullscreen_video.seekTo(currentPosition)
Log.d(TAG, "initializePlayer: seeked to $currentPosition")
}
然后我得到了这个日志
2020-12-08 13:12:53.548 28006-28006/com.skb.skara D/VideoViewActivity: onStart: 2677
2020-12-08 13:12:53.550 28006-28006/com.skb.skara D/VideoViewActivity: initializePlayer: seeked to 2677
2020-12-08 13:12:53.550 28006-28006/com.skb.skara D/VideoViewActivity: onStart: 2677
有人请解释这个行为并解释作用域函数的使用apply{}
看下面的table,范围内也是,this.currentPosition
是fullscreen_video.currentPosition
,而不是你的var currentPosition
Kotlin 的作用域运算符就像一把瑞士军刀,每个场景都有一个方法。
https://kotlinlang.org/docs/reference/scope-functions.html
Function | Object reference | Return value | Is extension function |
---|---|---|---|
let | it | Lambda result | Yes |
run | this | Lambda result | Yes |
run | - | Lambda result | No: called without the context object |
with | this | Lambda result | No: takes the context object as an argument. |
apply | this | Context object | Yes |
also | it | Context object | Yes |
它对于 DSL API 以及在创建一个简单的 Java 对象后调用多个 setter 非常有用。
val x = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
init(null as KeyStore?)
}
在这种形式中,不完整的对象在完全构造之前永远不可用。所以可以直接赋值给一个字段(忽略并发和内存壁垒)。
而且还保持表达式形式的内容,因此您可以链接运算符,而不是强制改变值。
这是一个示例,其中 also
很有用。
fun getRandomInt(): Int {
return Random.nextInt(100).also {
writeToLog("getRandomInt() generated value $it")
}
}
如果您切换到 also,它应该会更清楚地说明您的情况。
小心,VideoView
有自己的currentPosition。在其 apply
块内访问 currentPosition
将获得 VideoView
.
private fun initializePlayer() {
fullscreen_video.apply {
setVideoPath(videoUrl)
seekTo(currentPosition) // This will use VideoView.currentPosition
Log.d(TAG, "initializePlayer: seeked to $currentPosition") // This, too
}
}
关于apply
的解释:
The context object is available as a receiver (
this
). Andthis
always can be omitted.
如果要访问上面声明的 currentPosition
,请使用 this@YourActivity.currentPosition
。将 YourActivity
替换为您的 activity.