【问题标题】:Android: Abstract custom view and common layout inflationAndroid:抽象自定义视图和常见布局膨胀
【发布时间】:2020-03-06 16:22:06
【问题描述】:

所以,我做了一些研究,似乎抽象基类的init/构造函数中的视图膨胀并不是真正的最佳实践。我知道这是因为基类初始化程序发生在派生类的 init/ 构造函数之前。由于抽象类不是最终类,因此有一条关于thisinit 块中泄露的很好的IDE 消息。

这就是我所追求的:

abstract class Foo @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    private val myView: View

    init {
        // todo@patches fix leaking "this"
        View.inflate(context, R.layout.view_foo, this)
        myView = requireNotNull(findViewById(R.id.my_view))
    }
}
class Bar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : Foo(context, attrs, defStyleAttr) 

我真的不想在派生类的 init 中添加任何内容,也不想让 myView 成为稍后在抽象类中设置的可空/可变变量。

有没有其他人觉得这有点令人沮丧或有什么建议?从基类中扩展相同的布局似乎并不少见。

【问题讨论】:

  • 这能回答你的问题吗? Leaking this in constructor warning
  • 很抱歉,但事实并非如此。它仅建议抑制警告,并没有提供真正修复此警告的替代方法。它也与视图无关,对 Android 有不同的约束。
  • 一般建议是不要在构造函数中工作,因此我建议将这个逻辑移到其他地方。重构代码以便此类采用已初始化的myView 是可行的方法。

标签: android kotlin android-view android-custom-view


【解决方案1】:

在构造函数中泄漏this 是危险的,因为您将其泄漏到的对象可能在构造函数完成之前就开始访问其成员,因此它可能还没有准备好。即使是不可为空的 Kotlin 属性或其他奇怪的行为,您也可以获得 NPE。

LayoutInflator.inflate 的情况下,这似乎不是问题,因为Android 的内置视图经常将this 作为父级传递给inflate() 方法。例如,DatePicker 的构造函数实例化了 DatePickerSpinnerDelegate,它将 DatePicker 实例传递给 inflate(),这一切都发生在 DatePicker 的构造函数返回之前。

当您将视图作为父视图传递给inflate() 时,通过跟踪调用链,我看到父视图发生了两件事。它在该父级上调用getContext(),如果addToRoot 为真,它在该父级上调用addView()。所以我认为泄漏this 是安全的,只要你不覆盖addView() 来做依赖于你在调用inflate(). ButaddView()also internally callsrequestLayout()@987654334 后设置的成员的额外工作@invalidate()`,所以同样的问题也适用于那些。

在大多数情况下,您的自定义 ViewGroup 将是现有 Android ViewGroup 类的子类,因此您无需覆盖这些方法。

不幸的是,我们只能通过检查代码来推断这种行为。文档不能保证它是安全的,这并不令人非常放心,但据我所知,我们只需要接受它可能是安全的。也许应该在 AOSP 上打开一个问题。如果您用 Java 编写相同的代码,甚至不会出现此警告,但风险是相同的。

禁止警告不应该意味着您忽略警告或只是破解​​您的代码。它的意思是,“我承认失败模式并检查了我的代码不会以这种方式失败。”如果不是这种情况,那将是编译器错误,而不是警告。 在 Kotlin 中,可以使用的抑制注解是 @Suppress("LeakingThis")

【讨论】:

    猜你喜欢
    • 2013-07-24
    • 2011-05-18
    • 1970-01-01
    • 2015-10-31
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多