7

我有一个案例,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在这种情况下,当创建没有实例状态的 an 时,我们将得到以下异常:

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

请注意,造成这种情况的根本原因可能是onActivityCreated 文档 没有提到Bundle可以为空,而onCreate 文档确实可以解释为什么简单的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注释在这里没有帮助。

4

1 回答 1

4

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

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

活动onCreate 标记为@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更有意义。但是,我可以理解该决定是为了迫使开发人员注意翻译后的代码并明确决定参数是否为Nullable

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

同样关于您的代码,Java Lint 应该给您一个关于您的 overridden 的警告onCreate,说您正在使用带注释的参数覆盖一个方法并且您没有注释它们。

于 2017-10-09T23:58:13.680 回答