【问题标题】:Why are non-null type properties of class obtained from WeakReference.get() changing to nullable为什么从 WeakReference.get() 获得的类的非空类型属性更改为可空
【发布时间】:2025-11-24 23:05:04
【问题描述】:

我正在尝试在需要引用该活动的活动中编写处理程序。如果我这样写

class MainActivity : AppCompatActivity() {
    private val mHandler = MainActivityHandler(this)

    class MainActivityHandler(val activity: MainActivity) : Handler() {
        override fun handleMessage(msg: Message?) {
            when(msg?.what) {
                MSG_CHANGE_TEXT -> {
                    activity.tv_logged.setText(R.string.title_main)
                    activity.mHandler.sendMessageDelayed(obtainMessage(SOMETHING), 3000)
                }
                // ...
            }
        }
    }
}

此代码按预期编译和工作。但是,如果我尝试像这样传递对活动的弱引用

class MainActivity : AppCompatActivity() {
    private val mHandler = MainActivityHandler(WeakReference(this))

    class MainActivityHandler(val activityRef: WeakReference<MainActivity>) : Handler() {
        private val activity
            get() = activityRef.get()

        override fun handleMessage(msg: Message?) {
            when(msg?.what) {
                MSG_CHANGE_TEXT -> {
                    activity?.tv_logged.setText(R.string.title_main)
                    activity?.mHandler.sendMessageDelayed(obtainMessage(SOMETHING), 3000)
                }
                // ...
            }
        }
    }
}

现在编译器抱怨 tv_loggedmHandler 是可为空的接收器类型,需要使用 ? 访问。 我可以理解处理程序中的val activity: MainAcitivity? 可以为空,因为它来自 WeakReference.get() 但是为什么 MainActivity 中的属性也可以为空?

【问题讨论】:

    标签: android kotlin weak-references android-handler


    【解决方案1】:

    因为activity?.tv_logged 的返回类型是(假设它是TextView),TextView? .在 Kotlin docs 中,提出了通过if 条件检查null 的替代方法

    您的第二个选项是安全呼叫操作员,写成 ?。 b?.长度 如果 b 不为 null,则返回 b.length,否则返回 null。这个表达式的类型是 Int? .

    要只对非空值执行某种操作,可以将安全调用运算符与let一起使用:

     activity?.let{ //access activity via `it`}
    

    【讨论】:

    • 它有效。我可以在没有安全呼叫操作员的情况下访问 tv_logged in let 块。但是 tv_logged(或 mHandler)如何在活动的 let 块内更改为非空类型?为什么使用活动访问时 tv_logged 和 mHandler 可以为空?但在 Activity 中访问时不可为空?.let{} 块?
    【解决方案2】:

    当我在https://kotlinlang.org/docs/reference/null-safety.html#safe-calls阅读全文时,我明白了这一点

    正如我所怀疑的,这与 WeakReference 无关。发生这种情况是因为即使在访问非可空类型属性时,安全调用运算符也会返回可空类型。 (文档并没有真正明确地明确说明这一点。)

    【讨论】:

      最近更新 更多