我是Android开发和Kotlin的新手。
我正在关注Kotlin的第一个Android教程,我有这个方法调用:
val editText = findViewById<EditText>(R.id.editText)
findViewById
中android.app.Activity
的定义为:
@Nullable
public <T extends View> T findViewById(@IdRes int id)
Android Studio向我显示editText
的类型为EditText!
。我阅读了有关Java互操作性和平台类型的Kotlin文档,但是由于findViewById
用android.annotation.Nullable
进行了注释,editText
是受支持的可空性注释列表中的(according to Kotlin documentation),所以我希望{{{ 1}}类型推断为EditText?
。
我看到将代码更改为:
val editText = findViewById<EditText?>(R.id.editText)
但是为什么需要这样做,而@Nullable
却被忽略了?
答案 0 :(得分:1)
该方法可以为空,但您的类说明不是。我已经反编译了我的一个APK,发现了以下内容。
这是一个简单的Kotlin方法:
private fun setAppName() {
val name = view.findViewById<TextView>(R.id.app_name)
name.text = appInfo.appName
}
您可以将name
的规范视为TextView。
该方法在编译时会变成以下内容:
private final void setAppName() {
TextView textView = (TextView) this.view.findViewById(R.id.app_name);
Intrinsics.checkExpressionValueIsNotNull(textView, "name");
AppInfo appInfo = this.appInfo;
if (appInfo == null) {
Intrinsics.throwUninitializedPropertyAccessException("appInfo");
}
textView.setText(appInfo.getAppName());
}
请注意,它强制将findViewById
的返回值准确地放入括号中。就您而言,是EditText。
基本上,这使一切混乱。类似于这样做:
val view: View? = findViewById(R.id.whatever)
val castView: TextView = view as TextView
由于Kotlin如何处理类型推断,它有效地绕过了@Nullable
。
答案 1 :(得分:0)
在android.app.Activity
上设置的实际注释为@android.annotation.Nullable
。不可为空的对应对象是@android.annotation.NonNull
。这些不在Kotlin(see documentation)当前支持的“ Android可空性注释”中,而是在软件包com.android.annotations
和android.support.annotations
中声明的。
我打开了问题KT-27566,发现这些注释由于具有源保留而当前被忽略,因此它们在Kotlin编译器处理的编译字节码中不可用。
此外,根据KT-25279看来,似乎还有其他类似的注释,它们在软件包com.android.support
中定义,但也存在相同的问题。
我真的不明白,为什么Google会用可空性注释来搞乱(这么多不同的变体,其中有些对Kotlin集成没用,而它们的用处最大。)。