Android Livedata 没有更新 EditText

Android Livedata not updating EditText

我在 3 个不同的 EditText 中使用 Android LiveData。我必须显示将前两个 EditText 的值乘以第三个 EditText 的结果。我利用了这个网站上给我的建议,实际上第三个值是用前两个值相乘的结果更新的。问题是更新不会实时发生,而只会在我离开并重新进入 activity 时发生。我附上 XML 文件、activity 和视图模型。

XML:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">


<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    tools:context=".MainActivity">
         
            <EditText
                android:id="@+id/num1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:backgroundTint="@color/white"
                android:inputType="number" />

            <EditText
                android:id="@+id/num2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:backgroundTint="@color/white"
                android:inputType="numberDecimal" />

            <EditText
                android:id="@+id/num3"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:backgroundTint="@color/white"
                android:inputType="numberDecimal" />

    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Activity

class MainActivity: AppCompatActivity() {
private lateinit var binding: MainActivityBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)
    binding = DataBindingUtil.setContentView(
        this,
        R.layout.main_activity
    )

    viewModel=
        ViewModelProvider(this, factory)[MainActivityViewModel::class.java]

    initView(binding)
}

private fun initView(
    binding:
    MainActivityBinding
) {
    
        viewModel.num1.value = root?.num1?: 0
        viewModel.num2.value = root?.num2?: 0.0

       viewModel.num1.observe(lifecycleOwner, Observer { newNum1->
            binding.num1.setText(
                newNum1.toString()
            )
        })

        viewModel.num2.observe(lifecycleOwner, Observer { newNum2->
            binding.num2.setText(
                newNum2.toString()
            )
        })

binding.num1.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {

                viewModel.num1.value =
                    binding.num1.text?.toString()?.toInt()
                        ?: 0

            }

            override fun beforeTextChanged(
                s: CharSequence?,
                start: Int,
                count: Int,
                after: Int
            ) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                
            }
        })

        binding.num2.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {

                viewModel.num2.value =
                    binding.num2.text?.toString()?.toDouble()
                        ?: 0.0

            }

            override fun beforeTextChanged(
                s: CharSequence?,
                start: Int,
                count: Int,
                after: Int
            ) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

            }
        })

        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) {
                        binding.num3.setText((first * second).toString())
                    }
                }
            )
    }

    binding.num1.isFocusableInTouchMode = true
    binding.num2.isFocusableInTouchMode = true
    binding.num3.isFocusableInTouchMode = true

}

}

ViewModel

class RapportiAltriCostiViewModel(private val repositoryDB: DbRepository) : ViewModel() {


var num1= MutableLiveData<Int>()
var num2= MutableLiveData<Double>()
}

有大佬知道怎么解决吗?

感谢您的耐心等待和帮助!

更新

我尝试使用 TextWatcher,但它进入了循环:

binding.num1.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {

            viewModel.num1.value =
                binding.num1.text?.toString()?.toInt()
                    ?: 0

        }

        override fun beforeTextChanged(
            s: CharSequence?,
            start: Int,
            count: Int,
            after: Int
        ) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

        }
    })

    binding.num2.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {

            viewModel.num2.value =
                binding.num2.text?.toString()?.toDouble()
                    ?: 0.0

        }

        override fun beforeTextChanged(
            s: CharSequence?,
            start: Int,
            count: Int,
            after: Int
        ) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

        }
    })

我无法在分配值后删除 TextWatcher,正如我在网站上阅读的另一个问题一样,因为我需要它们始终倾听。

再次感谢您的耐心等待!

类似的东西。为避免循环更新,您可以将 onFirstChanged/onSecondChanged 中的新值与 liveData 中的值进行比较,然后以这种方式跳过 liveData.value = newValue。

class MainActivity : AppCompatActivity() {
    private lateinit var binding: MainActivityBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        binding = DataBindingUtil.setContentView(
            this,
            R.layout.main_activity
        )

        viewModel =
            ViewModelProvider(this, factory)[MainActivityViewModel::class.java]

        initView(binding)
    }

    private fun initView(
        binding:
        MainActivityBinding
    ) {
        binding.num1.listenChanges { viewModel.onFirstChanged(it) }
        binding.num2.listenChanges { viewModel.onSecondChanged(it) }

        viewModel.num1
            .observe(
                lifecycleOwner,
                Observer { num1Value ->
                    binding.num1.setText(num1Value.toString())
                }
            )
        viewModel.num2
            .observe(
                lifecycleOwner,
                Observer { num2Value ->
                    binding.num2.setText(num2Value.toString())
                }
            )
        viewModel.num3
            .observe(
                lifecycleOwner,
                Observer { result ->
                    binding.num3.setText(result.toString())
                }
            )
    }

    binding.num1.isFocusableInTouchMode = true
    binding.num2.isFocusableInTouchMode = true
    binding.num3.isFocusableInTouchMode = true

}

private fun EditText.listenChanges(textChanged: (String) -> Unit) {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
            textChanged(s.toString())
        }
    })
}

class RapportiAltriCostiViewModel(private val repositoryDB: DbRepository) : ViewModel() {

    val num1 = MutableLiveData<Int>(0)
    val num2 = MutableLiveData<Double>(0.0)
    val num3: LiveData<Double>
        get() = num1.combineWith(num2) { first, second ->
            (first ?: 0) * (second ?: 0.0)
        }

    fun onFirstChanged(newValue: Int) {
        if (num1.value != newValue) {
            num1.value = newValue
        }
    }

    fun onSecondChanged(newValue: Double) {
        if (num2.value != newValue) {
            num2.value = newValue
        }
    }

    private companion object {
        private fun <A, B, R> LiveData<A>.combineWith(b: LiveData<B>, combine: (A?, B?) -> R?): LiveData<R> =
            MediatorLiveData<R>().apply {
                var lastA: A? = this@combineWith.value
                var lastB: B? = b.value

                addSource(this@combineWith) {
                    lastA = it
                    value = combine.invoke(lastA, lastB)
                }

                addSource(b) {
                    lastB = it
                    value = combine.invoke(lastA, lastB)
                }
            }
    }
}