【问题标题】:kotlin lateinit vs computed propertykotlin lateinit vs 计算属性
【发布时间】:2021-03-22 18:18:26
【问题描述】:

以下两种方法有什么区别或没有区别:

1.

private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}
private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    _binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}

以上示例代码来自:https://developer.android.com/topic/libraries/view-binding。一种将 lateinit 用于 Activity,另一种将一个 由可选 var 支持的计算属性 用于 Fragment。

似乎都在 Fragment 和 Activity 中工作,但这让我很好奇:Kotlin 语言有什么不同吗?

【问题讨论】:

    标签: android kotlin


    【解决方案1】:

    他们在 Fragment 示例中这样做的原因是,当 Fragment 视图与 Activity 分离时,它可能会被拆除和移除,然后在重新附加到同一 Fragment 实例时(在 onCreateView() 中)重新创建一个活动。在 Fragment 分离期间,原始绑定实例无效,因此使用可空属性 (_binding) 并在 onDestroyView() 中设置回空值(请参阅您链接的示例代码)以避免泄漏这些视图当它们不再有效时。

    但是在您的 Fragment 代码中的大多数地方,可以安全地假设 Fragment 已附加,因此返回非空绑定的 binding 属性是为了方便起见。这类似于requireContext()requireActivity(),它们比可空的contextactivity 更方便使用。您只需要避免在 Fragment 可能分离时使用它们。这可能发生在异步代码中,例如某些网络调用的回调中。

    在 Activity 中,他们使用lateinit,因为您无法在 Activity 完全构造之前初始化视图。您的第一个安全入口点是onCreate(),因此可以在此处设置属性。 lateinit 允许该属性不可为空,但仍然可以安全使用,只要您将其初始值设置在尽可能早的时间点,即onCreate()

    lateinit 不是 Fragment 的正确方法,因为在 Fragment 生命周期中的某些时间段,绑定是不存在的,因此您需要能够将其设置为 null。对于 Activity,您可以选择使用可为空的属性而不是 lateinit,但如果在您可以访问 Activity 成员期间它永远不能为空,则必须处理它的可空性是不切实际的。

    【讨论】:

    • 有道理,感谢您的精彩解释。
    • 但是......开发人员仍然需要知道绑定变量何时变得无效(或为空)并且不要使用它,对吗?我想一个实际的区别是,在这样的错误中,一个从 force-unwrap 产生空指针,或者是非法状态异常,这可能有点难以解决?
    • 它对 Fragment 是私有的,大概如果您在 Fragment 中使用代码,您就会知道生命周期。我想您可以通过将异常消息设置为 get() = _binding ?: error("Cannot access binding when Fragment is detached.") 来比使用 !! 更明确
    【解决方案2】:

    lateinit 允许您创建不可为空的数据对象,因此您在属性旁边看不到?。除此之外真的没有区别

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-11
      • 2020-04-14
      • 1970-01-01
      • 2022-11-22
      • 2021-10-13
      • 2022-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多