gpt4 book ai didi

android - Kotlin Android Extensions for Views 背后的编辑器魔法是什么?

转载 作者:搜寻专家 更新时间:2023-11-01 09:34:19 26 4
gpt4 key购买 nike

当我添加 kotlinx.android.synthetic.main.<layout-name>.view.* 形式的导入时对于 Kotlin 源代码,它会改变 Android Studio 编辑器的行为。具体来说,它现在考虑 View 类型的任何属性具有与分配了 id 的布局文件中的每个 View 相对应的属性。我假设我在一个不是 Activity 的类(class)里做这件事或 Fragment .

例如,假设我有一个 ViewHolder在源文件中声明并向其添加一个名为 x 的属性类型 View .此外,假设我有一个名为 item_test 的布局具有三个已分配 ID 的 View 声明,a , b , 和 c .当我使用 item_testlayout-name 添加上述表单的合成导入时突然x具有三个新属性,a , b , 和 c .或者,更准确地说,编辑器使它看起来像x。具有这些属性。

经过一番研究,我得出以下结论:

  • 添加布局 View ID 作为属性是盲目的。此类合成导入所暗示的任何 View ID 都将添加到类型为 View 的类的任何属性中。 (或 View 的子类)。这包括类继承的此类属性。

  • 由于属性是盲目添加的,因此开发人员有责任确保在访问合成属性之前分配对应于合成导入的运行时 View ,否则将抛出异常。

    <
  • 如果在一个文件中指定了两个或多个这样的导入,那么它们的 View ID 的并集将被盲目地添加到类型为 View 的所有类属性中。 .

  • 允许多次导入的目的是考虑到一个布局文件包含另一个布局文件的情况。

这些结论正确吗?

围绕此功能的实现是否还有其他有趣的微妙之处?

我使用的是 1.1.2-5 版的 kotlin-gradle-plugin。

最佳答案

如果我没理解错的话,你假设如下:

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
}
}

So it appears to me that any property that is of type View will have the synthetic properties associated with a synthetic import regardless of whether it is valid or not. So the extension implementation appears to be brute force and will not tip-off the developer if anything is wrong.

没错。
现在,item_test 导入本质上是 View 类的扩展属性(简化示例[1]):

val View.item_test get() = findViewById(R.id.item_test)

对于布局中的每个 View ,插件都会生成这些属性,并将它们放入它们的相关文件中。 ActivityFragment 也存在这些属性。
因此,当您调用 x.item_test 时,实际上是在调用 x.findViewById(R.id.item_test)[1]。< br/>编译后,插件会将这些调用替换回 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 的 View 层次结构中或 y,就像它们不存在于 findViewById 一样。如果 findViewById 调用返回 null,则值为 null 或抛出 KotlinNullPointerException


  • The addition of layout view ids as properties is done blindly. Any view id implied by a such a synthetic import is added to any property of the class that is of type View (or a subclass of View). This includes properties of such type inherited by the class.

是的,因为该属性是 View 上的扩展属性,如上所述。

  • Because the properties are added blindly it is incumbent upon the developer to ensure that the runtime view corresponding to the synthetic import is assigned before the synthetic properties are accessed or an exception will be thrown.

我不确定你在这里问什么。如果您的意思是您必须在调用 x.item_test 之前初始化 x,那就对了。此外,x 在其层次结构中应该有一个 View item_test

  • 如果在一个文件中指定了两个或多个这样的导入,那么它们的 View ID 的并集将被盲目地添加到 View 类型的所有类属性中。允许多次导入的目的是考虑到一个布局文件包含另一个布局文件的情况。

是的。


[1]:实际上,这些查找在幕后被缓存了。参见 Under the hood在文档中。

关于android - Kotlin Android Extensions for Views 背后的编辑器魔法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44685129/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com