Android 使用LiveData的SeekBar和EditText的进展
我有文本输入和SeekBar 我需要通过文本输入值(数字)来更改导引头的值,并通过导引头更改值来更改文本值。使用视图模型和实时数据绑定 所以,我在viewmodel类中有两个中介实时数据 视图模型:Android 使用LiveData的SeekBar和EditText的进展,android,kotlin,mvvm,viewmodel,android-livedata,Android,Kotlin,Mvvm,Viewmodel,Android Livedata,我有文本输入和SeekBar 我需要通过文本输入值(数字)来更改导引头的值,并通过导引头更改值来更改文本值。使用视图模型和实时数据绑定 所以,我在viewmodel类中有两个中介实时数据 视图模型: val progress: MediatorLiveData<Int> by lazy { MediatorLiveData<Int>() } val progressText: MediatorLiveData<String> by lazy { Mediato
val progress: MediatorLiveData<Int> by lazy { MediatorLiveData<Int>() }
val progressText: MediatorLiveData<String> by lazy { MediatorLiveData<String>() }
xml和数据绑定如下所示:
<AppCompatSeekBar android:id="@+id/seekbar"
style="@style/SeekerItemStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="@={viewModel.progress}" />
<EditText android:id="@+id/input_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewModel.progressText}" />
(考虑输入文本)
但是,这里我得到了无限循环,因为一个调停者的变化影响到另一个调停者,而另一个调停者的变化又回到了一个调停者
这里有解决这一逻辑的最佳实践和更聪明的解决方案吗?谢谢。您可以分别为搜索者和文本制作两对MediatorLiveData LiveData。例如,第一个MediatorLiveData观察搜索栏的更改,当应用更改时,它会更改EditText的LiveData,反之亦然:您有MediatorLiveData,它会在每次EditText中的内容更改时更改SeekBar的LiveData。您可以使用
创建一个新的LiveData对象,该对象在源LiveData值更改之前不会发出值。如果equals()生成false,则认为该值已更改
因此,通过使用distinctUntilChanged
,我们可以通过检查源实时数据的值是否已更改来停止无限循环
如果您使用的是livedata ktx库,则可以使用以下代码
init {
progress.apply { addSource(progressText.distinctUntilChanged()) { postValue(it.toInt()) }}
progressText.apply { addSource(progress.distinctUntilChanged()) { postValue(it.toString()) }}
}
init {
progress.apply { addSource(Transformations.distinctUntilChanged(progressText)) { postValue(it.toInt()) }}
progressText.apply { addSource(Transformations.distinctUntilChanged(progress)) { postValue(it.toString()) }}
}
如果您没有使用livedata ktx库,则可以使用以下代码
init {
progress.apply { addSource(progressText.distinctUntilChanged()) { postValue(it.toInt()) }}
progressText.apply { addSource(progress.distinctUntilChanged()) { postValue(it.toString()) }}
}
init {
progress.apply { addSource(Transformations.distinctUntilChanged(progressText)) { postValue(it.toInt()) }}
progressText.apply { addSource(Transformations.distinctUntilChanged(progress)) { postValue(it.toString()) }}
}
这里不需要MediatorLiveData
-MutableLiveData
就足够了,因为您只需要能够更改值
对于progress
来说,只有一个LiveData
就足够了,而且里面应该有一个Int
值
现在代码是:
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
open class BasicViewModel: ViewModel() {
val progress: MutableLiveData<Int> by lazy { MutableLiveData<Int>() }
}
最后,您的活动可以如下所示:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.setLifecycleOwner(this)
val viewModel = ViewModelProviders.of(this).get(BasicViewModel::class.java)
binding.viewModel = viewModel
}
}
编辑:
val progress: MediatorLiveData<Int> by lazy { MediatorLiveData<Int>() }
val progressText: MediatorLiveData<String> by lazy { MediatorLiveData<String>() }
如果EditText
中的文本与SeekBar
中的值不相同,则方法将不同。然而,有一个LiveData
对象来实现这样的场景仍然足够了。因此,让我们想象一下,EditText
应该显示一个浮点值,如progress/100
。然后,它可以如下所示:
BasicViewModel.kt
package com.example.android.databinding.basicsample.data
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
open class BasicViewModel: ViewModel() {
val progressLiveData = MutableLiveData("0.0")
fun updateEditText(percentage: Int) {
progressLiveData.value = percentage.toFloat().div(100).toString()
}
fun onEditTextTyped(): LiveData<Int> {
return Transformations.switchMap(progressLiveData, {
val liveData = MutableLiveData<Int>()
try {
liveData.value = it.toString().toFloat().times(100f).toInt()
} catch (e: NumberFormatException) {
// reset the progress bar if the progress text is invalid
liveData.value = 0
}
liveData
})
}
}
package com.example.android.databinding.basicsample.data
导入androidx.lifecycle.LiveData
导入androidx.lifecycle.MutableLiveData
导入androidx.lifecycle.Transformations
导入androidx.lifecycle.ViewModel
开放类BasicViewModel:ViewModel(){
val progressLiveData=MutableLiveData(“0.0”)
fun updateEdit文本(百分比:Int){
progressLiveData.value=percentage.toFloat().div(100).toString()
}
fun onEditTextTyped():LiveData{
返回Transformations.switchMap(progressLiveData{
val liveData=MutableLiveData()
试一试{
liveData.value=it.toString().toFloat().times(100f).toInt()
}捕获(e:NumberFormatException){
//如果进度文本无效,请重置进度条
liveData.value=0
}
实时数据
})
}
}
活动\u main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.android.databinding.basicsample.data.BasicViewModel"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/input_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewModel.progressLiveData}" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="@{viewModel.onEditTextTyped}"
android:onProgressChanged="@{(seekBar, progress, fromUser) -> viewModel.updateEditText(progress)}" />
</LinearLayout>
</layout>