Android中Java方法可空返回值引发的Kotlin空安全问题
避免Handler创建时使用!!操作符的几种方案
方案1:使用checkNotNull()显式校验
checkNotNull()会在值为null时抛出IllegalStateException,同时可添加自定义错误信息,既规避了!!的不安全,也能在极端异常场景下给出明确提示,静态分析工具也不会报错:
private lateinit var myHandler: MyHandler val executor = Executors.newSingleThreadExecutor() executor.execute { Looper.prepare() myHandler = MyHandler(checkNotNull(Looper.myLooper()) { "调用Looper.prepare()后,当前线程的Looper必须存在" }) Looper.loop() } private inner class MyHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { super.handleMessage(msg) // 处理消息逻辑 } }
方案2:用?: error()替代强制断言
通过Elvis操作符配合error()函数,在null时抛出带自定义信息的异常,语义更直观,同样能通过静态分析检查:
private lateinit var myHandler: MyHandler val executor = Executors.newSingleThreadExecutor() executor.execute { Looper.prepare() val looper = Looper.myLooper() ?: error("Looper.prepare()已调用,Looper不应为null") myHandler = MyHandler(looper) Looper.loop() } private inner class MyHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { super.handleMessage(msg) // 处理消息逻辑 } }
方案3:使用HandlerThread封装Looper管理
这是更推荐的实践方式,HandlerThread是Android官方提供的专门用于处理Handler消息的线程类,内部已经封装了Looper.prepare()和Looper.loop()的逻辑,线程启动后looper属性一定非空,完全不需要手动处理Looper初始化:
private lateinit var myHandler: MyHandler // 创建并启动HandlerThread val handlerThread = HandlerThread("BackgroundHandlerThread") handlerThread.start() // 直接获取已初始化的Looper myHandler = MyHandler(handlerThread.looper) private inner class MyHandler(looper: Looper) : Handler(looper) { override fun handleMessage(msg: Message) { super.handleMessage(msg) // 处理消息逻辑 } } // 注意:在不需要时记得调用handlerThread.quit()或quitSafely()终止线程
核心逻辑说明
根据Android源码,Looper.prepare()会为当前线程创建并绑定Looper实例,之后调用Looper.myLooper()必然返回该实例,不会为null。上述方案均基于这个语义,用更安全的方式替代强制断言,同时保留异常场景下的错误提示能力。
内容的提问来源于stack exchange,提问作者Abu Yousuf
相关产品推荐
相关产品推荐

