如果我理解正确,您假设以下内容:
import kotlinx.android.synthetic.main.activity_main.item_test
import kotlinx.android.synthetic.main.activity_main.item_test_2
class MyClass {
lateinit var x: View
lateinit var y: View
fun foo() {
val foo1 = x.item_test // Compiles
val foo2 = y.item_test // Compiles as well
val bar1 = x.item_test_2 // Compiles too
val bar2 = y.item_test_2 // Compiles yet again
}
}
因此,在我看来,任何 View 类型的属性都将具有与合成导入关联的合成属性,无论它是否有效。因此,扩展实现似乎是蛮力的,如果有任何问题,也不会向开发人员报告。
那是对的。
现在,item_test
导入本质上是View
类的扩展属性(简化示例[1]):
val View.item_test get() = findViewById(R.id.item_test)
对于布局中的每个视图,插件都会生成这些属性,并将它们放在它们的相关文件中。这些性质也存在于Activity
和上Fragment
。
因此,当您调用 时x.item_test
,您实际上是在调用x.findViewById(R.id.item_test)
[1]。
编译后,插件会将这些调用替换回findViewById
. 所以上述程序[1]的简化反编译版本(Java):
final class MyClass {
public View x;
public View y;
public final void foo() {
TextView foo1 = (TextView) x.findViewById(id.item_test);
TextView foo2 = (TextView) y.findViewById(id.item_test);
TextView bar1 = (TextView) x.findViewById(id.item_test_2);
TextView bar2 = (TextView) y.findViewById(id.item_test_2);
}
}
由于这只是 上的扩展功能View
,因此没有健全性检查来检查 or 的视图层次结构中是否存在item_test
,就像它们不存在一样。如果调用返回,则值 is或 a被抛出。x
y
findViewById
findViewById
null
null
KotlinNullPointerException
- 将布局视图 ID 添加为属性是盲目的。这种合成导入所隐含的任何视图 id 都将添加到视图类型(或视图的子类)的类的任何属性中。这包括类继承的这种类型的属性。
是的,因为该属性是 上的扩展属性View
,如上所述。
- 由于属性是盲目添加的,因此开发人员有责任确保在访问合成属性之前分配与合成导入对应的运行时视图,否则将引发异常。
我不确定你在这里问什么。如果您的意思是您必须x
在调用之前进行初始化x.item_test
,那就对了。此外,x
应该item_test
在其层次结构中有一个视图。
- 如果在一个文件中指定了两个或多个此类导入,则它们的视图 ID 的并集将被盲目添加到 View 类型的所有类属性中。允许多个导入的目的是考虑一个布局文件包含另一个布局文件的情况。
是的。
[1]:实际上,这些查找在幕后被缓存。请参阅文档中的幕后花絮。