以下类有一个非常独特的生命周期,这需要我暂时清空lateinit
属性
class SalesController : BaseController, SalesView {
@Inject lateinit var viewBinder: SalesController.ViewBinder
@Inject lateinit var renderer: SalesRenderer
@Inject lateinit var presenter: SalesPresenter
lateinit private var component: SalesScreenComponent
override var state = SalesScreen.State.INITIAL //only property that I want to survive config changes
fun onCreateView(): View { /** lateinit variables are set here */ }
fun onDestroyView() {
//lateinit variables need to be dereferences here, or we have a memory leak
renderer = null!! //here's the problem: throws exception bc it's a non-nullable property
} }
以下是框架使用它的方式。
controller.onCreateView() //same instance of controller
controller.onDestroyView() //same instance of controller
controller.onCreateView() //same instance of controller
controller.onDestroyView() //same instance of controller
我的lateinit
属性是由dagger注入的,我需要将它们设置为null
中的onDestroyView
- 或者有内存泄漏。然而,就我所知(没有反思)而言,这在kotlin中是不可能的。我可以使这些属性可以为空,但这会破坏Kotlin无效安全的目的。
我不太清楚如何解决这个问题。理想情况下,某些类型的注释处理器会生成java代码以在onDestroyView
中自动清空特定变量吗?
答案 0 :(得分:7)
Kotlin lateinit
属性使用null
作为未初始化的标记值,并且没有在null
属性的支持字段中设置lateinit
的干净方法没有反思。
但是,Kotlin允许您使用委托属性覆盖属性行为。似乎没有委托允许在kotlin-stdlib
中使用,但如果你需要这种行为,你可以implement your own delegate这样做,为你的工具添加一些代码:
class ResettableManager {
private val delegates = mutableListOf<ResettableNotNullDelegate<*, *>>()
fun register(delegate: ResettableNotNullDelegate<*, *>) { delegates.add(delegate) }
fun reset() { delegatesToReset.forEach { it.reset() } }
}
class Resettable<R, T : Any>(manager: ResettableManager) {
init { manager.register(this) }
private var value: T? = null
operator fun getValue(thisRef: R, property: KProperty<*>): T =
value ?: throw UninitializedPropertyAccessException()
operator fun setValue(thisRef: R, property: KProperty<*>, t: T) { value = t }
fun reset() { value = null }
}
用法:
class SalesController : BaseController, SalesView {
val resettableManager = ResettableManager()
@set:Inject var viewBinder: SalesController.ViewBinder by Resettable(resettableManager)
@set:Inject var renderer: SalesRenderer by Resettable(resettableManager)
@set:Inject var presenter: SalesPresenter by Resettable(resettableManager)
fun onDestroyView() {
resettableManager.reset()
}
}
答案 1 :(得分:0)
我认为您需要的是一个正常的健康nullable
财产,没有lateinit
的疯狂:
class SalesController : BaseController, SalesView {
@Inject @JvmField var viewBinder: SalesController.ViewBinder? = null
使用此解决方案,编译器会要求您检查viewBinder
是否null
,但IMO在此处是合适的,因为它可以在您的程序的任何位置变为null
。< / p>