[英]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.