gpt4 book ai didi

未删除 token 类型 Int 或 Long 的 Android 处理程序回调 (*Kotlin)

转载 作者:行者123 更新时间:2023-12-02 12:45:00 24 4
gpt4 key购买 nike

我在 Kotlin android 项目中执行了这段代码,它将记录两条消息。如果我将 token 更改为 CharString 它将仅打印一条消息,这是所需的行为。 Android 中的 java 项目中的相同用例可以正常工作。

    val handler = Handler()
//val token1: Long = 1001L
//val token2: Int = 121
val token1: Long = 1001L
val token2: Int = 1002

handler.postAtTime(
{
Log.e("postAtTime 1", " printed 1 ")
handler.removeCallbacksAndMessages(token2)
},
token1,
SystemClock.uptimeMillis() + 2000
)

handler.postAtTime(
{
Log.e("postAtTime 2", " printed 2 ")
},
token2,
SystemClock.uptimeMillis() + 4000
)

我的问题是,为什么在 Kotlin 中,对于 IntLong 类型的标记,处理程序不会删除回调?

编辑如果我尝试使用注释值,它会起作用

最佳答案

MessageQueue 中的代码(处理消息删除)是 doing this :

while (p != null && p.target == h
&& (object == null || p.obj == object)) {

// clearing code
}

其中 p 是队列中的消息,p.obj 是与其关联的 token ,object 是您可以选择的 token 。已传入以清除消息。因此,如果您传入一个 token ,并且它与当前消息的 token 匹配,则该消息将被清除。

问题是它使用引用相等来比较 token - 如果它们不是完全相同的对象,如果您没有传入发布消息的同一 token 实例,则它不匹配并且不会发生任何情况。


当您将 token2 声明为 Int(这是 Kotlin 自己的“一种原语”),然后将其传递给需要实际对象的方法时,它被装箱为一个Integer。您会执行两次 - 一次是使用 token 发布消息,一次是使用 token 清除消息。它每次都会创建一个不同的(非引用相等)对象。

您可以通过存储 token 对象并比较它们来测试这一点:

val handler = Handler()
//val token1: Long = 1001L
//val token2: Int = 121
val token1: Long = 1001L
val token2: Int = 1002

var postedToken: Any? = null
var cancelledToken: Any? = null

fun postIt(r: ()->Unit, token: Any, time: Long): Any {
handler.postAtTime(r, token, time)
return token
}

fun cancelIt(token: Any): Any {
handler.removeCallbacksAndMessages(token)
return token
}

postIt(
{
Log.e("postAtTime 1", " printed 1 ")
cancelledToken = cancelIt(token2)
// referential equality, triple-equals!
Log.e("Comparing", "Posted === cancelled: ${postedToken === cancelledToken}")
},
token1,
SystemClock.uptimeMillis() + 2000
)

postedToken = postIt(
{
Log.e("postAtTime 2", " printed 2 ")
},
token2,
SystemClock.uptimeMillis() + 4000
)
E/Comparing: Posted === cancelled: false

至于为什么它可以使用 121 的 Int,我假设它与 Java 的整数缓存有关。在幕后,Kotlin 代码(如果您执行 Show Bytecode 然后反编译它)正在调用 Integer.valueOf(token2)Here's what the docs say about it :

Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

因此调用Integer(number)总是创建一个新对象,valueOf(number)可能创建一个,或者它可能返回一个之前创建的Integer对象。值 121 将始终返回与之前相同的对象,这就是为什么您会获得与该对象的引用相等性,因此标记匹配。对于较大的数字,您将获得不同的对象(您可以在调试器中检查它们的 ID)


但是为什么它可以在 Java 中运行,而不能在 Kotlin 中运行?我没有使用 Java 进行测试,但缓存的工作方式可能不同,也许编译器能够更智能地为“明确缓存”范围之外的 int 变量重用同一对象。或者,如果您在 Java 代码中将标记定义为 Integer 而不是 int,那么您将创建一个对象并两次传递它,因此始终会这样匹配。

无论如何,呃,这是很多背景知识,可以尝试帮助您找出它为什么会损坏!简而言之,不要这样做,不要让它自动装箱,创建一个 token 对象并保留对它的引用,以便稍后可以再次传递相同的实例;)

(这也适用于String - Java有一个字符串池,如果你声明一个字符串文字两次,它会重用同一个对象,但它可能不会,所以将 String 分配给变量更安全,然后您就知道它始终是同一个对象)

关于未删除 token 类型 Int 或 Long 的 Android 处理程序回调 (*Kotlin),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62405834/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com