首页 > 解决方案 > 如何重置 LiveData当 LiveData在 Android Studio 中的双向数据绑定中更改了吗?

问题描述

layout_detail.xml中EditText使用双向数据绑定和Button使用单向数据绑定

我希望Button将在aDetailViewModel.aMVoice.name更改时启用。

当 EditText 的内容改变时,aMVoicein的值DetailViewModel也会改变,我想我可以重新设置 的值isChanged,但我不知道该怎么办?你能不能告诉我?

layout_detail.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">

    <data>
        <import type="android.view.View" />
        <variable name="aDetailViewModel"
            type="info.dodata.voicerecorder.viewcontrol.DetailViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <EditText
            android:id="@+id/eTName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:inputType="textPersonName"
            android:text="@={aDetailViewModel.aMVoice.name}" />

        <Button
            android:id="@+id/btnSave"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:enabled="@{aDetailViewModel.isChanged}"
            android:text="Save" />

    </LinearLayout>

</layout>

代码

class DetailViewModel(private val mDBVoiceRepository: DBVoiceRepository, private val voiceId:Int) : ViewModel() {

   val aMVoice=mDBVoiceRepository.getVoiceById(voiceId)     //I hope to reset isChanged when aMVoice is changed

   val isChanged: LiveData<Boolean> = MutableLiveData<Boolean>(false)    
}
  

class DBVoiceRepository private constructor(private val mDBVoiceDao: DBVoiceDao){
    fun getVoiceById(id:Int)=mDBVoiceDao.getVoiceById(id)
}

@Dao
interface DBVoiceDao{      
   @Query("SELECT * FROM voice_table where id=:id")
   fun getVoiceById(id:Int):LiveData<MVoice>
}

@Entity(tableName = "voice_table", indices = [Index("createdDate")])
data class MVoice(
    @PrimaryKey (autoGenerate = true) @ColumnInfo(name = "id") var id: Int = 0,
    var name:          String = "",
    var path:          String = "",  
)

标签: androidkotlinandroid-databindingandroid-livedata

解决方案


当您想找出多个属性的值变化时,我们应该在特定的LiveDataviamap转换中将每个属性分开。这些LiveDatanews起到双向绑定的作用。

最后,要集成更改,最好的方法是使用 aMediatorLiveData被每个更改触发,然后检查值。DB因此,检查初始值与从视图中接收到的值是否相等就足够了。

class DetailViewModel(...) {

    private val aMVoice = mDBVoiceRepository.getVoiceById(voiceId)

    val voiceName = aMVoice.map { it.name } as MutableLiveData<String>
    val voicePath = aMVoice.map { it.path } as MutableLiveData<String>
    // ... (similar for more attributes)

    val isChanged = MediatorLiveData<Boolean>().apply {
        addSource(voiceName) { postValue(currentMVoice != aMVoice.value) }
        addSource(voicePath) { postValue(currentMVoice != aMVoice.value) }
        // ... (similar for more attributes)
    }

    // it collects current values delivered from views as a `MVoice` object.
    private val currentMVoice: MVoice?
        get() = aMVoice.value?.copy(
            name = voiceName.value ?: "",
            path = voicePath.value ?: "",
            // ... (similar for more attributes)
        )
}

然后在布局中使用voiceName,voicePath等:

<EditText
    android:id="@+id/eTName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:inputType="textPersonName"
    android:text="@={aDetailViewModel.voiceName}" />

<EditText
    android:id="@+id/eTPath"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:text="@={aDetailViewModel.voicePath}" />

// ...

要使用map转换,请不要忘记添加lifecycle-livedata-ktx依赖项,build.gradle如果您以前没有的话。

implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'

推荐阅读