Код в MessageQueue
(обрабатывающий удаление сообщения): делаем это:
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
// clearing code
}
где p
— сообщение в очереди, p.obj
— связанный с ним токен, а object
— необязательный токен, который вы передали для очистки сообщений. Таким образом, если вы ввели токен, и он совпадает с токеном текущего сообщения, сообщение очищается.
Проблема в том, что он использует ссылочное равенство для сравнения токенов - если они не являются одним и тем же объектом, если вы не передаете тот же экземпляр токена, с которым отправили сообщение, он не совпадает, и ничего не происходит.
Когда вы объявляете token2
как Int
, который является собственным типом примитива Kotlin, а затем передаете его в метод, который требует фактического объекта, он помещается в Integer
. И вы делаете это дважды — один раз, чтобы опубликовать сообщение с токеном, и один раз, чтобы удалить сообщения с токеном. Каждый раз он создает другой (не равный по ссылкам) объект.
Вы можете проверить это, сохранив объекты токена и сравнив их:
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
Что касается того, почему он работает с Int
из 121, я предполагаю, что это связано с целочисленным кешем Java. Под капотом код Kotlin (если вы сделаете Show Bytecode
, а затем декомпилируете его) вызывает Integer.valueOf(token2)
. Вот что говорится об этом в документации:
Возвращает экземпляр Integer, представляющий указанное значение int. Если новый экземпляр Integer не требуется, этот метод обычно следует использовать вместо конструктора Integer(int), так как этот метод, скорее всего, даст значительно лучшую производительность пространства и времени за счет кэширования часто запрашиваемых значений. . Этот метод всегда будет кэшировать значения в диапазоне от -128 до 127 включительно и может кэшировать другие значения за пределами этого диапазона.
Таким образом, вызов Integer(number)
будет всегда создавать новый объект, valueOf(number)
может создать его или может возвращать объект Integer
, созданный ранее. Значение 121 всегда возвращает тот же объект, что и раньше, поэтому вы получаете ссылочное равенство с этим, поэтому токены совпадают. Для большего числа вы получаете разные объекты (вы можете проверить их идентификаторы в отладчике)
Но почему это работает на Java, а не на Котлине? Я не тестировал Java, но, возможно, кеш работает по-другому, возможно, компилятор может быть умнее при повторном использовании одного и того же объекта для переменной int
за пределами определенно кэшированного диапазона. Или, если вы определяете свой токен в своем Java-коде как Integer
вместо int
, вы создаете один объект и передаете его оба раза, так что это всегда будет совпадать.
Во всяком случае, это много предыстории, чтобы попытаться помочь вам понять, почему он ломается! Короткая версия: не делайте этого, не позволяйте ему автоматически упаковывать вещи, создайте объект токена и сохраните ссылку на него, чтобы вы могли снова передать тот же экземпляр позже;)
(Это относится и к String
s — в Java есть пул строк, где он повторно использует один и тот же объект, если вы дважды объявляете строковый литерал, но это может быть и нет, поэтому безопаснее присвоить String
переменной, и тогда вы знаете, что это всегда один и тот же объект)
person
cactustictacs
schedule
25.08.2020
char
, в java это правильно, но здесь ведет себя иначе, чемint
? - person Ultimo_m   schedule 16.06.2020