如果我理解正确的,我们假定你是以下几点:
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
}
}
所以,在我看来,这是类型查看任何属性将有一个合成导入相关的综合性能,无论是否它是否有效。因此,扩展实现看起来是蛮力的,如果有什么错误的话,不会提醒开发人员。
这是正确的。现在
,所述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
一个扩展函数时,不存在完整性检查,以检查是否存在于视图层次item_test
x
或y
,就像他们不存在findViewById
一样。如果findViewById
呼叫返回null
,则值为null
或KotlinNullPointerException
被引发。
- 加法布局视图id的作为属性被盲目地进行。任何由这样的综合导入暗示的视图id都被添加到View类型的任何属性(或View的子类)中。这包括由类继承的这种类型的属性。
是,由于属性是基于View
一个扩展特性,如上所述。
- 由于属性被盲目地加入它是在所述显影剂有责任确保相应于合成进口运行时视图被访问的合成属性之前或分配一个异常将被抛出。
我不确定你在问什么。如果你的意思是你在调用x.item_test
之前必须初始化x
,那就对了。另外,x
的层次结构中应该有一个视图item_test
。
- 如果在一个文件中指定了两个或多个这样的导入,那么它们的view id的联合会被盲目地添加到View类型的所有类属性中。 允许多次导入的目的是解释一个布局文件包含另一个布局文件的情况。
是的。
[1]:其实,在幕后这些查找被缓存。请参阅文档中的Under the hood。
@roobyroo我对你的问题作了另一种解释,这是否更好? – nhaarman
我已经按照承诺回复了这个问题。 – roobyroo
@roobyroo请参阅答案的补充。 – nhaarman