首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

kotlin 开发采一小坑,朋友们请注意!

工作项目中已经使用了 kotlin,有一个 view 需要展示 5 秒钟将其关闭并做一些其他工作,我用了View.postDelayed(runnable , delayMillis) 方法,大家都知道考虑到这是一个延迟任务,有可能在 Runnable 还未执行到的时候用户就把页面关闭了,所以在页面关闭时需要把 Runnable 给移除掉。

简化了例子如下面代码:

上面这段代码好像没什么问题,上面声明了一个 (以为是)Runnable 对象,一个 lambda 表达式的写法,点击 textView 5 秒后执行 Runnable,run 方法里 show 了一个 Toast,onDestroy 时移除 Runnable。正常的情况在你 移除这个 Runnable 之后,Runnable 里的操作就不会再响应,也就是收不到这个Toast消息了,然而事实并非所愿,关闭页面后依然收到了 Toast。这是为什么?实在找不出哪里有问题,于是我用 Java 代码试了一遍,发现 Java 果然没问题,移除 Runnable 后就不会弹Toast,既然 Java 没问题,那问题是不是出在 kotlin 语法上?

于是我看 kotlin 编译后的 Java 代码

编译后的 Runnable 发现是个Function0 而不是 Runnable, 在调用 postDelayed方法之前new 一个 Runnable 它把 Function0 传了进去,这个 Runnable 它的构造方法有一个 Function0 参数,run 方法里调用的是 Function0 的 invoke 方法

其实这都不是重点,即使这样它依然不应该影响我想要的结果,重点是在 onDestroy 方法里它又 new 一个 runnable 对象,并且 removeCallbacks() 移除的是这个刚 new 出来的 Runnable

这下就真相大白了,原因是 view.postDelayed 的 Runnable 和 remove 的 Runnable 不是一个对象,所以才会出现移除不掉的情况。

现在看下 Runnable 这样写:

看出区别了吗?上面的例子是这样的:

‘=’ 后面多了这个 Runnable,再看编译后的 Java 代码

这回它直接 new了 Runnable 对象,而不是 Function0 了,onDestroy 里 remove 的是同一个 Runnable,所以仅仅是写法上少写了一个 Runnable 就出现这么大的差别,而且还不容易发现,简是直见了鬼。

因为 Runnable 和 Function 刚好只有一个方法,都可以用 lamdba 表达式 ,创建的时候没有声明是 Runnable,所以这个时候程序不知道你要的是 Runnable,只好是 Function,当你调用 postDelayed 的时候才知道你需要一个 Runnable,这时候才给你创建出来。我们在享受 kotlin 语法带来的便捷时也要注意其中的坑。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181125G0O9EM00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券