0

I have 3 editext and I have to multiply the numbers written in the first two, and make the result appear live on the third using Android Livedata.

viewModel.num1.observe(this,
    Observer { newNum1-> binding.ediText1.text = newNum1.toString() }

viewModel.num2.observe(this,
    Observer { newNum2-> binding.ediText2.text = newNum2.toString() }

viewModel.num3.observe(this,
    Observer { newNum3-> binding.ediText3.text = newNum3.toString() }

I tried something like this, with 2 MutableLiveData and one MediatorLivedata, but i did something wrong because it didn't update live the third EditText. Could someone help me?

class MyViewModel : ViewModel() {
    private var num1 = MutableLiveData<Int>();
    private var num2 = MutableLiveData<Double>();
    private var mun3 = MediatorLiveData<Double>();

    num3.addSource(num1, this::onChanged);
    num3.addSource(num2, this::onChanged);
  
    
    private fun onChanged(x : Double) {
        var a = num1.value
        var b = num2.value

        if (a== null)
            a= 0;
        if (b== null)
            b= 0.0;
        
        num3.setValue(a * b);
    }
}

I'm using Kotlin but i accept any kind of code, even in java.

Thank you for your patience and help!

Best regards, Mark.

qwerty123
  • 43
  • 4

2 Answers2

0

That might not be your literal code, because it's not compileable. You can't pass the same function to be used as the observer for either source, since the source types are different.

Your onChanged() function doesn't use the input parameter, so you can remove that and call it from a lambda you pass to each addSource call.

You can also simplify the content of your function by using Elvis operators.

private val num1 = MutableLiveData<Int>()
private val num2 = MutableLiveData<Double>()
private val num3 = MediatorLiveData<Double>().apply {
    addSource(num1) { onChanged() }
    addSource(num2) { onChanged() }
}

private fun onChanged() {
    val a = num1.value ?: 0
    val b = num2.value ?: 0.0
    num3.value = a * b
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • Thanks! It works fine, but the EditText don't update live because all three editText are in the same view. It is updated just when i exit from the view and come back into the view. Do you know how could i make it work live? – qwerty123 May 18 '21 at 08:08
0

Please try something like that, but be aware of nullability. One of received values can be null

fun <A, B> LiveData<A>.combineWith(b: LiveData<B>): LiveData<Pair<A?, B?>> =
MediatorLiveData<Pair<A?, B?>>().apply {
    var lastA: A? = this@combineWith.value
    var lastB: B? = b.value

    addSource(this@combineWith) {
        lastA = it
        value = Pair(lastA, lastB)
    }

    addSource(b) {
        lastB = it
        value = Pair(lastA, lastB)
    }
}

viewModel.num1
    .combineWith(viewModel.num2)
    .observe(
        this, 
        Observer { (first, second) -> 
            if (first != null && second != null) {
                 someEditText.text = (first * second).toString()
            }
        }
    )
Romadro
  • 626
  • 4
  • 10
  • Thanks! It works fine, but the EditText don't update live because all three editText are in the same view. It is updated just when i exit from the view and come back into the view. Do you know how could i make it work live? – qwerty123 May 18 '21 at 08:08
  • @qwerty123 This is a different problem. Please provide us with code of your activity or fragment and your ViewModel to help us figure out your problem. I believe there is a problem with the way you are updating two source live datas. Or maybe it will be better to post it as new question on Stackoverflow – Romadro May 18 '21 at 09:22
  • Ok Thanks, i posted a new Question with the Code: https://stackoverflow.com/questions/67586779/livedata-not-updating-edittext – qwerty123 May 18 '21 at 13:03