从Kotlin实现Java接口时出现NullPointerException

Gia*_*nMS 8 java interface nullpointerexception kotlin rx-java2

我正在尝试BiFunction从Kotlin中的RxJava 实现接口,并且得到了NullPointerException

这是我在Kotlin中实现的Java接口。来自RxJava 2。

package io.reactivex.functions;

import io.reactivex.annotations.NonNull;

/**
 * A functional interface (callback) that computes a value based on multiple input values.
 * @param <T1> the first value type
 * @param <T2> the second value type
 * @param <R> the result type
 */
public interface BiFunction<T1, T2, R> {

    /**
     * Calculate a value based on the input values.
     * @param t1 the first value
     * @param t2 the second value
     * @return the result value
     * @throws Exception on error
     */
    @NonNull
    R apply(@NonNull T1 t1, @NonNull T2 t2) throws Exception;
}
Run Code Online (Sandbox Code Playgroud)

这是我的实现

class MonitoringStateReducer: BiFunction<MonitoringViewState, MonitoringResult, 
    MonitoringViewState> {
    override fun apply(
        previousState: MonitoringViewState,
        result: MonitoringResult
    ): MonitoringViewState {
        when (result) {
           //Returns a non-null new state
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在ViewModel中,我尝试使用它,但是它抛出NullPointerException。

2019-08-22 09:57:41.049 6925-6925 / com.name.app E / AndroidRuntime:致命例外:主进程:com.name.app,PID:6925 java.lang.RuntimeException:无法启动活动ComponentInfo { com.name.app/com.name.app.features.monitoring.presentation.MonitoringActivity}:java.lang.NullPointerException:累加器在android.app.android.ActivityThread.performLaunchActivity(ActivityThread.java:2907)为null。 android.app.ActivityThread.-wrap11(未知源:0)(位于android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1641))位于android.os.Handler.dispatchMessage上的ActivityThread.handleLaunchActivity(ActivityThread.java:2986) (Handler.java:105)在android.os.Looper.loop(Looper.java:164)在android.app.ActivityThread.main(ActivityThread.java:6694)在com.android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote.java:240)在java.lang.reflect.Method.invoke(本机方法)在com.android.internal.os.ZygoteInit.main( ZygoteInit.java:769)由以下原因引起:java.lang.NullPointerException:在io.reactivex.Observable.scanWith(Observable.java: 11537)位于com.name.app.features.monitoring.presentation.MonitoringViewModel.compose(MonitoringViewModel.kt:47)的io.reactivex.Observable.scan(Observable.java:11502) .presentation.MonitoringViewModel。(MonitoringViewModel.kt:18)位于com.name.app.features.monitoring.presentation.MonitoringViewModel_Factory。在com.name的dagger.internal.DoubleCheck.get(DoubleCheck.java:47)处的com.name.app.features.monitoring.presentation.MonitoringViewModel_Factory.get(MonitoringViewModel_Factory.java:8)处的get(MonitoringViewModel_Factory.java:25) com的androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)处的.app.di.viewmodel.ViewModelFactory.create(ViewModelFactory.kt:12)在com处的androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)。 name.app.features.monitoring.presentation.MonitoringActivity $ viewModel $ 2.invoke(MonitoringActivity.kt:46)位于com.name.app.features.monitoring.presentation.MonitoringActivity $ viewModel $ 2.invoke(MonitoringActivity.kt:26)位于com.name.app.features.monitoring.presentation上的kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)。在com.name.app.features.monitoring.presentation.MonitoringActivity.bind(MonitoringActivity.kt:85)处的MonitoringActivity.getViewModel(未知来源:7)在com.name.app.features.monitoring.presentation.MonitoringActivity.onCreate(MonitoringActivity) .kt:119)在android.app.Activity.performCreate(Activity.java:6984)在android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1235)在android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2860)在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1641)在android.app.ActivityThread $ -hrap11(Unknown Source:0)在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1641)在android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2986) android.os.Looper上的os.Handler.dispatchMessage(Handler.java:105)。在com.android.internal.os.Zygote $ MethodAndArgsCaller处的java.lang.reflect.Method.invoke(Native Method)在android.app.ActivityThread.main(ActivityThread.java:6694)处循环(Looper.java:164)。在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)上运行(Zygote.java:240)

class MonitoringViewModel @Inject constructor(
    private val processor: MonitoringProcessor
) : BaseViewModel<MonitoringIntention, MonitoringViewState>() {
    //Properties that are not relevant for the question

    private val reducer: MonitoringStateReducer = MonitoringStateReducer()

    private fun compose(): Observable<MonitoringViewState> {
        return intentsSubject.compose(intentFilter)
            .map(actionFromIntent)
            .compose(processor)
            .scan(MonitoringViewState.init(), reducer) //Exception is here
            .distinctUntilChanged()
            .replay(1)
            .autoConnect(0)
    }

    override fun state(): Observable<MonitoringViewState> = compose()

    //Functions that are not relevant for the question
}
Run Code Online (Sandbox Code Playgroud)

该代码也不起作用。

private val reducer by lazy(LazyThreadSafetyMode.NONE) {
    MonitoringStateReducer()
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我用此代码替换化径器,它将起作用。

private val reducer: BiFunction<MonitoringViewState, MonitoringResult, MonitoringViewState>
    get() = MonitoringStateReducer()
Run Code Online (Sandbox Code Playgroud)

在Kotlin 1.3.40和1.3.50上测试。

Val*_*kov 10

问题来自Kotlin类的初始化顺序。崩溃是由于以下事实造成的:BaseViewModel构造函数正在调用state()MonitoringViewModel类中重写的方法。结果,当reducer访问时,它尚未初始化。在构造派生类的新实例期间,第一步将完成基类初始化,并且初始化要在派生类的初始化逻辑运行之前进行。看一下这篇文章,它描述了一个非常相似的问题。派生类初始化顺序 Kotlin的文档部分也应该很有用。

  • 相关:[构造函数中的可重写方法调用出了什么问题](/sf/ask/238301101/) (2认同)

Ben*_* P. 1

我怀疑堆栈跟踪的这一部分包含了答案:

at com.name.app.features.monitoring.presentation.MonitoringViewModel_Factory.get(MonitoringViewModel_Factory.java:8)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
at com.name.app.di.viewmodel.ViewModelFactory.create(ViewModelFactory.kt:12)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
Run Code Online (Sandbox Code Playgroud)

我从中得出的结论是,您正在使用 Dagger 创建MonitoringViewModel类的实例。我不确定Dagger 是否执行我将要描述的操作,但我知道其他库(如 Gson)会执行此操作,并且它符合该模式......

如果使用该类,则可以在不实际调用构造函数的情况下创建对象的实例Unsafe。请参阅本文的“避免初始化”部分:http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/

如果这种情况发生在这里,那么您的代码private val reducer = MonitoringStateReducer()将永远不会真正被执行,因为这是类初始化的一部分。因此,reducer永远不会初始化,并且是null当您尝试在compose().

我不确定为什么这会使其在使用by lazy委托时不起作用,但它确实解释了为什么它在您提供自定义时起作用get():它不再是类初始化的一部分,而是根据需要进行评估。

尝试在不使用 Dagger 的情况下创建此类的实例,并查看“正常”初始化是否有效。