0

I have alot of repeated code, and since I'm fairly new to Kotlin, I want to learn and try to take advantage of it as much as possible. I have many lazily declared MutableLiveData<Int> properties, and somewhere down the code I'm checking each one to make sure that the live data's value will never go below 0. I thought using Kotlin's delegates would work but I feel like I'm at a lost.

Here's a snippet of my declaration (defaulting the value to 0).

    private val count: MutableLiveData<Int> by lazy {
        MutableLiveData<Int>().also { it.value = 0 }
    }

Here's a snippet of some onClickListeners.

    btn_decrement.setOnClickListener {
        count.value?.run {
            if (this > 0) {
                count.value = this - 1
            }
        }
    }

I want to do something like the following:

    private val d4Count: MutableLiveData<Int> by lazy {
        MutableLiveData<Int>().also { it.value = 0 }
    }
    set(value) {
        if (field.value?.toInt() - value < 0) field.value = 0 else field.value -= value
    }

But Android Studio is giving me 2 errors:

  1. A 'val'-property cannot have a setter. This makes sense, but is there a way to keep count immutable, but change MutableLiveData<Int>'s setter to something similar as my attempt?

  2. Delegated property cannot have accessors with non-default implementations. I don't really know what this means, but I'm assuming this is key to me achieving what I want.

How do I go about doing this, or am I looking at this wrong? Is there a better way to do what I want?

2 Answers2

0

First, that is not how you use MutableLiveData. You set the value by using setValue (on main threadorpostValue` (on any thread).

val d4Count = MutableLiveData<Int>()

status.value = 4
status.postValue(4)

If you want to change the setter of MutableLiveData, you can either extends MutableLiveData (1) or create a setter method (2).

(1)

class CustomIntLiveData: MutableLiveData<Int>() {
    override fun setValue(value: Int?) {
        super.setValue(processValue(value))
    }

    override fun postValue(value: Int?) {
        super.postValue(processValue(value))
    }

    private fun processValue(value: Int?) : Int {
        val currentValue = this.value
        return if (currentValue == null || value == null || currentValue - value < 0) {
            0
        } else {
            currentValue - value
        }
    }
}

(2)

fun setCount(value: Int?) {
    val currentValue = d4Count.value

    if (currentValue == null || value == null || currentValue - value < 0) {
        d4Count.value = 0
    } else {
        d4Count.value = currentValue - value
    }
}

Delegated property cannot have accessors with non-default implementations. I don't really know what this means, but I'm assuming this is key to me achieving what I want.

It means you can not use set if you use by.

Joshua
  • 5,901
  • 2
  • 32
  • 52
0

Using additional property can help you:

class SomeClass {
    var count = 0
        set(value) { 
            if (field - value < 0) field = 0 else field -= value
            _count.value = field
        }

    private val _count: MutableLiveData<Int> by lazy {
        MutableLiveData<Int>().also { it.value = 0 }
    }
}

// Using additional property
val s = SomeClass()
s.count = 5 // this will set value to `count` and `_count` properties depending on the condition in the setter of `count` property.
Sergio
  • 27,326
  • 8
  • 128
  • 149