【问题标题】:Java to Kotlin converter and nullable method argumentsJava 到 Kotlin 转换器和可为空的方法参数
【发布时间】:2017-10-09 23:25:38
【问题描述】:

我有一个案例,Java 到 Kotlin 的转换器因为没有将方法参数标记为可为空而使我悲惨地失败了。

示例:使用registerActivityLifecycleCallbacks跟踪活动生命周期:

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}

    @Override
    public void onActivityStarted(Activity activity) {}

    @Override
    public void onActivityResumed(Activity activity) {}

    // ... other overriden methods
});

将此代码粘贴到 Kotlin 结果:

registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle) {}

    override fun onActivityStarted(activity: Activity) {}

    override fun onActivityResumed(activity: Activity) {}

    override fun onActivityPaused(activity: Activity) {}

    // ... other overriden methods (all with non-nullable parameters)
})

问题是savedInstanceState 参数类型是Bundle,它应该是Bundle?,因为它的值可以是null

在这种情况下,当Activity 在没有实例状态的情况下创建时,我们将得到以下异常:

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter savedInstanceState

注意,造成这种情况的根本原因可能是 onActivityCreated documentation 没有提到 Bundle 可以为 nullonCreate documentation 这样做可以解释为什么简单的 onCreate 转换可以作为预期:

// Java
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
}
// Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
}

我的问题是我们如何知道哪些参数应该可以为空以防止此类问题? @Nullable 注释在这里没有帮助。

【问题讨论】:

    标签: java android kotlin kotlin-android-extensions kotlin-null-safety


    【解决方案1】:

    如果注释没有帮助,我认为没有办法知道参数是否可以为空。

    关于您发布的代码,我想我知道发生了什么:

    活动onCreateIS标记为@Nullable

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        final AppCompatDelegate delegate = getDelegate();
        delegate.installViewFactory();
        delegate.onCreate(savedInstanceState);
        .
        .
    

    虽然ActivityLifecycleCallbacks 接口方法不是:(参见Application.java

    public interface ActivityLifecycleCallbacks {
        void onActivityCreated(Activity activity, Bundle savedInstanceState);
        void onActivityStarted(Activity activity);
        void onActivityResumed(Activity activity);
        void onActivityPaused(Activity activity);
        void onActivityStopped(Activity activity);
        void onActivitySaveInstanceState(Activity activity, Bundle outState);
        void onActivityDestroyed(Activity activity);
    }
    

    显然 Kotlin 翻译器正在处理注释,但默认使用 Non-Null,在我看来这并不常见,因为考虑非注释参数更有意义 可以为空。但是我可以理解这个决定是为了迫使开发人员注意翻译后的代码并明确决定参数是否为 Nullable

    顺便说一句,请注意有几个 @NonNull@Nullable 注释(javax、android、jetbrains ...)如果 Kotlin 翻译器只能识别其中的一些,我不会感到惊讶(但这只是一个猜测)

    另外关于您的代码,Java Lint 应该就您的覆盖 onCreate 向您发出警告,说您正在使用带注释的参数覆盖一个方法并且您没有对它们进行注释。

    【讨论】:

    • 我想这支持你的论点:kotlinlang.org/docs/reference/…。将尝试再次使用注释进行转换(之前对我不起作用)
    • 是的,Kotlin 假设 Java 代码默认不为空,除非它有注解。它使用! 表示Java 代码,例如String! 告诉您代码来自Java。
    猜你喜欢
    • 2018-02-01
    • 2023-02-15
    • 1970-01-01
    • 1970-01-01
    • 2020-05-11
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    相关资源
    最近更新 更多