2017-02-22 11 views
8

以下のクラスは、一時的に出てヌルlateinit性質nullにlateinit Kotlinプロパティを設定する方法

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プロパティは短剣によって注入されている、と私はonDestroyViewnullにそれらを設定する必要があります - またはメモリリークを持っています。これは、私が知っている限り(反射なしで)、kotlinでは可能ではありません。私はこれらのプロパティをnullにすることができますが、それはKotlinのnull安全性の目的を無効にします。

私はこれを解決する方法はあまりよく分かりません。理想的には、onDestroyViewに特定の変数を自動的にヌルにするJavaコードを生成するアノテーションプロセッサがありますか?

+0

なぜ漏れがありますか?おそらく、問題はSalesControllerのプロパティではなく、SalesControllerにありますか?私は、漏れの問題を避けるためにDaggerによって注入されたプロパティをnullに明示的に設定する必要はありませんでした。 – Massimo

+0

@Massimo指揮者のコントローラインスタンスは設定の変更を生き残っていますhttps://github.com/bluelinelabs/Conductor – ZakTaccardi

+0

それらを無効にする必要がある場合、あなたは 'lateinit'をする必要はありません。そして、私はそこにどんなリークもないと確信しています、あなたはちょうどいくつかの定義を混ぜています。プレゼンターがあなたのビューを参照する場合はリークしません。 – Dimezis

答えて

7

Kotlin lateinit特性が初期化されていないフラグ値としてnullを使用し、反射することなく、lateinit性のバッキングフィールドにnullを設定するためのない清浄な方法がありません。


ただし、Kotlinでは、委任されたプロパティを使用してプロパティの動作をオーバーライドできます。そのkotlin-stdlibにできます何のデリゲートがありませんように思えるが、あなたはまさにこの動作が必要な場合は、次のことができimplement your own delegateはあなた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() 
    } 
} 
+0

「代理人を持つメンバープロパティ」に「@ Inject」を持つことはできませんでした。 – mfulton26

+0

@ mfulton26、コメントありがとう!それが '@set:Inject'で動作すると思いますか? – hotkey

+0

良い考え。私はそれが(私はダガーや何かを使用していないと思うが、少なくともコンパイル)。 – mfulton26

0
私は何が必要だと思う

lateinitのmadgicせずに正常な健康nullableプロパティです:

class SalesController : BaseController, SalesView { 
    @Inject @JvmField var viewBinder: SalesController.ViewBinder? = null 

このソリューションコンパイラでは、viewBindernullかどうかを確認するよう求められますが、プログラムの任意の時点でnullになる可能性があるため、IMOは適切です。

+0

これは機能しません。すべてがヌル可能な場合、私は2つを区別する方法がなく、私たちは再びJavaのヌル安全性の問題に戻ります – ZakTaccardi

関連する問題