以下のクラスには非常にユニークなライフサイクルがあり、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
プロパティは短剣によって挿入され、null
でonDestroyView
に設定する必要があります。そうしないと、メモリリークが発生します。ただし、これは、私が知る限り(反省なしで)、kotlinでは不可能です。これらのプロパティをnull可能にすることはできますが、それではKotlinのnull安全性の目的が無効になります。
これを解決する方法がよくわかりません。理想的には、onDestroyView
で特定の変数を自動的に無効にするJavaコードを生成する、ある種の注釈プロセッサが存在する可能性がありますか?
Kotlin lateinit
プロパティは初期化されていないフラグ値としてnull
を使用し、リフレクションなしでnull
プロパティのバッキングフィールドにlateinit
を設定するクリーンな方法はありません。
ただし、Kotlinでは、委任されたプロパティを使用してプロパティの動作をオーバーライドできます。 kotlin-stdlib
にそれを許可するデリゲートがないようですが、この動作が正確に必要な場合は、 独自のデリゲートを実装 して、utilsにコードを追加できます。
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()
}
}
必要なのは、nullable
の狂気のない通常の健全なlateinit
プロパティだと思います。
class SalesController : BaseController, SalesView {
@Inject @JvmField var viewBinder: SalesController.ViewBinder? = null
このソリューションでは、コンパイラはviewBinder
がnull
であるかどうかを確認するように求めますが、IMOは、プログラムの任意の時点でnull
になる可能性があるため、ここでは適切です。