我收到以下错误消息:
FATAL EXCEPTION: main
Process: com.example.myapp.debug, PID: 27111
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:583)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:573)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1049)
Caused by: com.example.ConfException: ... is NULL!
at com.example.SingletonInstance.getInstance(SingletonInstance.kt:21)
at com.example.ServiceClientCtxConf$Companion.getInstance(Unknown Source:2)
at com.example.AppClientConf$Companion.setConf(AppClientConf.kt:52)
at com.example.activities.MyActivity.onCreate(MyActivity.kt:200)
...
从
MyActivity
开始,我在提到的第 200 行进行 REST 调用:
AppClientConf
.setConf() // line 200
.doOnNext { successful ->
//
}
.subscribe()
而这是
AppClientConf
简化后的样子(上面的错误消息行):
class AppClientConf private constructor() {
companion object {
fun setConf(): Observable<Boolean> =
ServiceClientConf
.setConf(context = ServiceClientCtxConf.instance) // line 52
.onErrorReturnItem(false)
}
}
由于抛出的
ConfException: ... is NULL!
在错误日志中,ServiceClientCtxConf.instance
似乎是 null
以及进一步提到的 ServiceClientCtxConf
:
class ServiceClientCtxConf(
val serviceClient: IServiceClient = ServiceClient()
) {
companion object : ISingletonInstance<ServiceClientCtxConf> by SingletonInstance()
}
有了这个
SingletonInstance
:
interface ISingletonInstance<T> {
var instance: T
}
class SingletonInstance<T> : ISingletonInstance<T> {
private var singletonInstance: T? = null
override var instance: T
set(value) {
singletonInstance = value
}
get() = singletonInstance ?: throw ConfException("... is NULL!") // get is here line 21
}
SingletonInstance::set()
是否从未被 ServiceClientCtxConf.instance
隐式调用?
我在这里缺少什么?
没有人调用
SingletonInstance#instance#set
方法。
首先,Kotlin 中的属性只是一个类字段,提供了 setter 和 getter。如果属性具有非基本类型,则其默认初始化值为 null。
其次,
companion object
是一个单例,并且在第一次调用时延迟初始化。当其类型是接口时,必须提供实现。这就是 provided by
功能发挥作用的地方。在您的案例中,实现由 SingletonInstance()
提供。
最后,当调用
.setConf(context = ServiceClientCtxConf.instance)
时,它会转换为ServiceClientCtxConf.Companion.instance
并执行getter。由于没有通过 set
提供任何值,因此返回默认值。
使用
companion object
进行构造不会隐式调用 set
方法。此外,作为一个单身人士,它甚至没有对 ServiceClientCtxConf
的引用。
要解决此问题,需要显式将
ServiceClientCtxConf
设置为 Companion.instance
。