Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin lazy default property

Tags:

android

kotlin

In Kotlin, how do i define a var that has a lazy default value ?

for example, a val would be something like this:

val toolbarColor  by lazy {color(R.color.colorPrimary)}

What i want to do is, have a default value for some property (toolbarColor), and i can change that value for anything else. Is it possible?

EDIT: This does the partial trick.

var toolbarColor = R.color.colorPrimary
    get() = color(field)
    set(value){
        field = value
    }

Is it possible to ease this by writing

var toolbarColor = color(R.color.colorPrimary)
    set(value){
        field = value
    }

in a way that the default value is computed lazily? At the moment it won't work because color() needs a Context that is only initialized later.

like image 206
johnny_crq Avatar asked Dec 18 '15 00:12

johnny_crq


People also ask

What is lazy keyword in Kotlin?

Lazy is mainly used when you want to access some read-only property because the same object is accessed throughout. That's it for this blog.

Is lazy thread safe in Kotlin?

It is lazy and thread-safe, it initializes upon first call, much as Java's static initializers. You can declare an object at top level or inside a class or another object.

How do you use lazy in Kotlin example?

Example. In this example, we will declare a lazy variable "myName" and we could see that the call to this parts of the code will happen only once and when the value is initialized, it will remember the value throughout the application. Once the value is assigned using lazy initialization, it cannot be reassigned .

What is the difference between lazy and Lateinit?

lateinit can only be used with a var property whereas lazy will always be used with val property. A lateinit property can be reinitialised again and again as per the use whereas the lazy property can only be initialised once.


1 Answers

You can create your own delegate method:

private class ColorDelegate<T>(initializer: () -> T) : ReadWriteProperty<Any?, T> {

    private var initializer: (() -> T)? = initializer

    private var value: T? = null

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: initializer!!()
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

Declare in some delegate:

object DelegatesExt {
    fun <T> lazyColor(initializer: () -> T): ReadWriteProperty<Any?, T> = ColorDelegate(initializer)
}

And use as follow:

var toolbarColor by DelegatesExt.lazyColor {
    // you can have access to your current context here.
    // return the default color to be used
    resources.getColor(R.color.your_color)
}

...

override fun onCreate(savedInstanceState: Bundle?) {
    // some fun code
    // toolbarColor at this point will be R.color.your_color
    // but you can set it a new value
    toolbarColor = resources.getColor(R.color.new_color)
    // now toolbarColor has the new value that you provide.
}

I think this could be a cleaner way to do, but I don't know yet (starting with kotlin few days ago). I will take a look and see if this could be done with less code.

like image 79
Deividi Cavarzan Avatar answered Sep 25 '22 22:09

Deividi Cavarzan