[英]NullPointerException when implementing Java interface from Kotlin
我正在尝试在Kotlin中实现BiFunction
接口,我得到一个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;
}
这是我的实施
class MonitoringStateReducer: BiFunction<MonitoringViewState, MonitoringResult,
MonitoringViewState> {
override fun apply(
previousState: MonitoringViewState,
result: MonitoringResult
): MonitoringViewState {
when (result) {
//Returns a non-null new state
}
}
}
然后,在ViewModel中,我尝试使用它,但它会抛出NullPointerException。
2019-08-22 09:57:41.049 6925-6925 / com.name.app E / AndroidRuntime:FATAL EXCEPTION:main进程: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.app.ActivityThread.performLaunchActivity(ActivityThread.java:2907)中,accumulator为null。 Activity.Thread.handleLaunchActivity(ActivityThread.java:2986)位于android.app.Handler.dispatchMessage上的android.app.ActivityThread.-wrap11(未知来源:0)android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1641) (Handler.java:105)位于android.app.Looper.loop(Looper.java:164)的android.app.ActivityThread.main(ActivityThread.java:6694),位于java.lang.reflect.Method.invoke(Native方法) )com.android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote.java:240)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)引起:java.lang.NullPointerException: accumu lator在io.reactivex.internal.function.ObjectHelper.requireNonNull(ObjectHelper.java:39)处于空白处于io.reactivex.Observable.scanWith(Observable.java:11537)io.reactivex.Observable.scan(Observable.java: 11502)com的com.name.app.features.monitoring.presentation.MonitoringViewModel.compose(MonitoringViewModel.kt:47)位于com的com.name.app.features.monitoring.presentation.MonitoringViewModel。(MonitoringViewModel.kt:18)。 name.app.features.monitoring.presentation.MonitoringViewModel_Factory.get(MonitoringViewModel_Factory.java:25)位于dagger.internal.DoubleCheck的com.name.app.features.monitoring.presentation.MonitoringViewModel_Factory.get(MonitoringViewModel_Factory.java:8)。在androidx.lifecycle.ViewModelProvider的androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)的com.name.app.di.viewmodel.ViewModelFactory.create(ViewModelFactory.kt:12)获取(DoubleCheck.java:47) .get(ViewModelProvider.java:130)at com.name.app.features.monitoring.presentation.MonitoringActivity $ viewMo del $ 2.invoke(MonitoringActivity.kt:46)at com.name.app.features.monitoring.presentation.MonitoringActivity $ viewModel $ 2.invoke(MonitoringActivity.kt:26)at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81) at com.name.app.features.monitoring.presentation.MonitoringActivity.getViewModel(Unknown Source:7)at com.name.app.features.monitoring.presentation.MonitoringActivity.bind(MonitoringActivity.kt:85)at com.name。 app.features.monitoring.presentation.MonitoringActivity.onCreate(MonitoringActivity.kt:119)at android.app.Activity.performCreate(Activity.java:6984)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1235)at android Android.app.ActivityThread $中android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2986)的android.app.ActivityThread.-wrap11(未知来源:0)的.app.ActivityThread.performLaunchActivity(ActivityThread.java:2860) H.handleMessage(ActivityThread.java:1641)位于android.os.Looper的android.os.Handler.dispatchMessage(Handler.java:105) .loop(Looper.java:164)位于android.app.ActivityThread.main(ActivityThread.java:6694)的java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.Zygote $ MethodAndArgsCaller com.android.internal.os.ZygoteInit.main。(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
}
这段代码也不起作用。
private val reducer by lazy(LazyThreadSafetyMode.NONE) {
MonitoringStateReducer()
}
但是,如果我用这个代码替换reducer,它就可以了。
private val reducer: BiFunction<MonitoringViewState, MonitoringResult, MonitoringViewState>
get() = MonitoringStateReducer()
在Kotlin 1.3.40和1.3.50上测试。
@Valeriy Katkov的回答是正确的,请接受他的回答。
这是一个模拟相同场景的代码:
fun main() {
MonitoringViewModel()
}
open abstract class BaseViewModel {
init {
state()
}
abstract fun state()
}
class MonitoringViewModel: BaseViewModel() {
private val reducer1: MonitoringStateReducer = MonitoringStateReducer()
private val reducer2: BiFunction<MonitoringViewState, MonitoringResult, MonitoringViewState>
get() = MonitoringStateReducer()
override fun state() {
Observable.just(MonitoringResult(3))
.scan(MonitoringViewState(0), reducer1)
.subscribe { state -> println(state.value) }
}
}
data class MonitoringViewState(val value: Int)
data class MonitoringResult(val value: Int)
class MonitoringStateReducer : BiFunction<MonitoringViewState, MonitoringResult,
MonitoringViewState> {
override fun apply(
previousState: MonitoringViewState,
result: MonitoringResult
): MonitoringViewState {
return MonitoringViewState(previousState.value + result.value)
}
}
如果使用reducer1
使用scan
运算符运行此代码,您将看到异常:
线程“main”中的异常java.lang.NullPointerException:accumulator为null
如果使用reducer2
使用scan
运算符运行代码,则成功。
reduce1
时为什么会崩溃? 来自@Valeriy Katkov的回答 :
崩溃的原因是BaseViewModel构造函数正在调用在子MonitoringViewModel类中重写的state()方法。 结果,当访问reducer时,它还没有初始化。 在构造派生类的新实例期间,基类初始化作为第一步完成,并且它在派生类的初始化逻辑运行之前发生。
我怀疑堆栈跟踪的这一部分是否有答案:
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)
我从中获取的是您正在使用Dagger来创建MonitoringViewModel
类的实例。 我不确定 Dagger会做我将要描述的内容,但我知道其他库(如Gson)这样做,它符合模式......
如果使用Unsafe
类,则可以创建对象而不实际调用构造函数。 请参阅本文的“避免初始化”部分: http : //mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/
如果这发生在这里,那么你的private val reducer = MonitoringStateReducer()
将永远不会被执行,因为那是类初始化的一部分。 因此, reducer
从未初始化,并且当您尝试在compose()
使用它时为null
。
我不确定为什么在使用by lazy
委托时它会使它不起作用,但是当你提供自定义get()
时它确实有意义:它不再是类初始化的一部分,而是被评估一经请求。
尝试在不使用Dagger的情况下创建此类的实例,并查看“正常”初始化是否有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.