2016-03-02 16 views
16

तो मैं एंड्रॉयड के लिए kotlin उपयोग करें, और जब विचारों बढ़ा-चढ़ाकर, मैं निम्न कार्य के लिए करते हैं:Kotlin आलसी गुण और मान रीसेट: एक रीसेट आलसी प्रतिनिधि

private val recyclerView by lazy { find<RecyclerView>(R.id.recyclerView) } 

इस विधि काम करेंगे। हालांकि, एक ऐसा मामला है जिसमें यह ऐप को बग करेगा। यदि यह एक टुकड़ा है, और टुकड़ा बैकस्टैक पर जाता है, onCreateView फिर से बुलाया जाएगा, और खंड का दृश्य पदानुक्रम फिर से बनाया जाएगा। जिसका अर्थ है, आलसी शुरू किए गए रीसाइक्लर व्यू पुराने दृश्य को इंगित करेंगे जो अब अस्तित्व में नहीं है।

एक समाधान इस तरह है:

private lateinit var recyclerView: RecyclerView 

और onCreateView अंदर सभी गुण आरंभ।

मेरा सवाल है, क्या आलसी गुणों को रीसेट करने का कोई तरीका है ताकि उन्हें फिर से शुरू किया जा सके? मुझे लगता है कि तथ्य प्रारंभिक सभी कक्षाओं के शीर्ष पर किए जाते हैं, कोड को व्यवस्थित रखने में मदद करता है। विशिष्ट समस्या इस प्रश्न में पाई जाती है: kotlin android fragment empty recycler view after back

+0

क्या आप एक आलसी परिवर्तनीय चर की तलाश में हैं, जिसे आप निश्चित रूप से प्रारंभ कर सकते हैं लेकिन स्पष्ट रूप से सेट भी कर सकते हैं या आप लोडिंग कैश की तलाश कर रहे हैं जिसे आप पुनः लोड कर सकते हैं? – mfulton26

+0

मैं आलसी रूप से एक संपत्ति शुरू करना चाहता हूं, यदि आवश्यक हो तो इसे रीसेट करने के विकल्प के साथ। पहले प्रारंभिकरण से पहले राज्य होने का रीसेट करना –

+0

इसके लिए आपको एक कस्टम प्रतिनिधि की आवश्यकता है, यह लिखना अपेक्षाकृत आसान है। यदि आपके परिदृश्य का अक्सर उपयोग किया जाता है, तो इसे stdlib – voddan

उत्तर

17

यहां एक रीसेट करने योग्य आलसी का एक त्वरित संस्करण है, यह अधिक सुरुचिपूर्ण हो सकता है और थ्रेड सुरक्षा के लिए डबल चेक की आवश्यकता है, लेकिन यह मूल रूप से विचार है। आलसी प्रतिनिधियों के प्रबंधन (ट्रैक रखने) के लिए आपको कुछ चाहिए ताकि आप रीसेट के लिए कॉल कर सकें, और फिर चीजें जिन्हें प्रबंधित और रीसेट किया जा सके। इन प्रबंधन वर्गों में यह lazy() लपेटता है।

:

class Something { 
    val lazyMgr = resettableManager() 
    val prop1: String by resettableLazy(lazyMgr) { ... } 
    val prop2: String by resettableLazy(lazyMgr) { ... } 
    val prop3: String by resettableLazy(lazyMgr) { ... } 
} 

तो आलसी सब अगली बार पर नए मूल्यों पहुँचे जाने के लिए वापस जाना है बनाने के लिए:

यहाँ अपने अंतिम वर्ग तरह दिखेगा एक उदाहरण के रूप में, है

lazyMgr.reset() // prop1, prop2, and prop3 all will do new lazy values on next access 

द्वारा रीसेट आलसी के कार्यान्वयन:

class ResettableLazyManager { 
    // we synchronize to make sure the timing of a reset() call and new inits do not collide 
    val managedDelegates = LinkedList<Resettable>() 

    fun register(managed: Resettable) { 
     synchronized (managedDelegates) { 
      managedDelegates.add(managed) 
     } 
    } 

    fun reset() { 
     synchronized (managedDelegates) { 
      managedDelegates.forEach { it.reset() } 
      managedDelegates.clear() 
     } 
    } 
} 

interface Resettable { 
    fun reset() 
} 

class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init:()->PROPTYPE): Resettable { 
    @Volatile var lazyHolder = makeInitBlock() 

    operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE { 
     return lazyHolder.value 
    } 

    override fun reset() { 
     lazyHolder = makeInitBlock() 
    } 

    fun makeInitBlock(): Lazy<PROPTYPE> { 
     return lazy { 
      manager.register(this) 
      init() 
     } 
    } 
} 

fun <PROPTYPE> resettableLazy(manager: ResettableLazyManager, init:()->PROPTYPE): ResettableLazy<PROPTYPE> { 
    return ResettableLazy(manager, init) 
} 

fun resettableManager(): ResettableLazyManager = ResettableLazyManager() 

और कुछ इकाई परीक्षण सुनिश्चित करने के लिए:

class Tester { 
    @Test fun testResetableLazy() { 
     class Something { 
      var seed = 1 
      val lazyMgr = resettableManager() 
      val x: String by resettableLazy(lazyMgr) { "x ${seed}" } 
      val y: String by resettableLazy(lazyMgr) { "y ${seed}" } 
      val z: String by resettableLazy(lazyMgr) { "z $x $y"} 
     } 

     val s = Something() 
     val x1 = s.x 
     val y1 = s.y 
     val z1 = s.z 

     assertEquals(x1, s.x) 
     assertEquals(y1, s.y) 
     assertEquals(z1, s.z) 

     s.seed++ // without reset nothing should change 

     assertTrue(x1 === s.x) 
     assertTrue(y1 === s.y) 
     assertTrue(z1 === s.z) 

     s.lazyMgr.reset() 

     s.seed++ // because of reset the values should change 

     val x2 = s.x 
     val y2 = s.y 
     val z2 = s.z 

     assertEquals(x2, s.x) 
     assertEquals(y2, s.y) 
     assertEquals(z2, s.z) 

     assertNotEquals(x1, x2) 
     assertNotEquals(y1, y2) 
     assertNotEquals(z1, z2) 

     s.seed++ // but without reset, nothing should change 

     assertTrue(x2 === s.x) 
     assertTrue(y2 === s.y) 
     assertTrue(z2 === s.z) 
    } 
} 
1

मैं एक ही काम किया था, और यह मैं क्या उपयोग किया जाता है:

import kotlin.properties.ReadOnlyProperty 
import kotlin.reflect.KProperty 

class SingletonLazy<T : Any>(val initBlock:() -> T, val clazz: Class<T>) { 
    operator fun <R> provideDelegate(ref: R, prop: KProperty<*>): ReadOnlyProperty<R, T> = delegate() 

    @Suppress("UNCHECKED_CAST") 
    private fun <R> delegate(): ReadOnlyProperty<R, T> = object : ReadOnlyProperty<R, T> { 
     override fun getValue(thisRef: R, property: KProperty<*>): T { 
      val hash = clazz.hashCode() 
      val cached = singletonsCache[hash] 
      if (cached != null && cached.javaClass == clazz) return cached as T 
      return initBlock().apply { singletonsCache[hash] = this } 
     } 
    } 
} 

private val singletonsCache = HashMap<Int, Any>() 

fun <T> clearSingleton(clazz: Class<T>) : Boolean { 
    val hash = clazz.hashCode() 
    val result = singletonsCache[hash] 
    if (result?.javaClass != clazz) return false 

    singletonsCache.remove(hash) 
    return true 
} 

inline fun <reified T : Any> singletonLazy(noinline block:() -> T): SingletonLazy<T> 
     = SingletonLazy(block, T::class.java) 

उपयोग:

val cat: Cat by singletonLazy { Cat() } 

fun main(args: Array<String>) { 
    cat 
    println(clearSingleton(Cat::class.java)) 
    cat // cat will be created one more time 
    println(singletonsCache.size) 
} 

class Cat { 
    init { println("creating cat") } 
} 

बेशक, आपके पास कैशिंग रणनीतियां हो सकती हैं।

संबंधित मुद्दे