如何重置LiveData<;布尔值>;当LiveData<;MVoice>;Android Studio中的双向数据绑定是否已更改?

如何重置LiveData<;布尔值>;当LiveData<;MVoice>;Android Studio中的双向数据绑定是否已更改?,android,kotlin,android-databinding,android-livedata,Android,Kotlin,Android Databinding,Android Livedata,在layout_detail.xml中,EditText使用双向数据绑定,按钮使用单向数据绑定 我希望在更改aDetailViewModel.aMVoice.name时启用该按钮 当EditText的内容更改时,DetailViewModel中的aMVoice的值也将更改,我想我可以重置isChanged的值,但我不知道怎么做?你能告诉我吗 布局_detail.xml <layout xmlns:android="http://schemas.android.com/apk/re

在layout_detail.xml中,EditText使用双向数据绑定,按钮使用单向数据绑定

我希望在更改
aDetailViewModel.aMVoice.name
时启用该按钮

当EditText的内容更改时,
DetailViewModel
中的
aMVoice
的值也将更改,我想我可以重置
isChanged
的值,但我不知道怎么做?你能告诉我吗

布局_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 = "",  
)
class-DetailViewModel(private-val-mDBVoiceRepository:DBVoiceRepository,private-val-voiceId:Int):ViewModel(){
val aMVoice=mdbvoicepositionory.getVoiceById(voiceId)//我希望在aMVoice更改时重置isChanged
val isChanged:LiveData=MutableLiveData(false)
}
类DBVoiceRepository私有构造函数(私有val mDBVoiceDao:DBVoiceDao){
fun getVoiceById(id:Int)=mDBVoiceDao.getVoiceById(id)
}
@刀
接口DBVoiceDao{
@查询(“从voice_表中选择*,其中id=:id”)
趣味getVoiceById(id:Int):LiveData
}
@实体(tableName=“voice_table”,Index=[Index(“createdDate”))
数据类MVoice(
@PrimaryKey(autoGenerate=true)@ColumnInfo(name=“id”)变量id:Int=0,
变量名称:String=“”,
变量路径:String=“”,
)
像那样试试看

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: MutableLiveData<Boolean> = MutableLiveData<Boolean>(false)

    fun listenChanges(owner: LifecycleOwner) {
        aMVoice.observe(owner) {
            isChanged.value?.apply {
                isChanged.value = !this
            }
        }
    }
}

当您想了解多个属性的值变化时,我们应该通过
map
转换在特定的
LiveData
中分离每个属性。这些新的
LiveData
s起着双向绑定的作用

最后,要集成更改,最好的方法是使用由每个更改触发的
中介livedata
,然后检查值。因此,检查
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)
        )
}

要使用
map
转换,请不要忘记在
build.gradle
中添加
lifecycle livedata ktx
依赖项

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

谢谢但是你的代码不起作用
val-aMVoice=mdbvoicepositionory.getVoiceById(voiceId).map{isChanged.postValue(true);当
aMVoice
的内容更改时,它}
将不会启动谢谢!但我想也许还有其他更好的方法。你知道我必须检查所有字段来定义它是否被更改,如果MVoice包括名称、路径、日期、描述、isFavorited等等,这是一项复杂的工作。不客气!我再次进行了更新,以满足检查更多属性的要求:)谢谢,但我认为您的代码无法运行,我无法理解什么是
isChanged.value=!这意味着尝试一下——它可能需要一些定制。如果您不理解这部分代码,这意味着您并不真正了解Kotlin及其应用程序。此外,根据当前的执行线程,您可能需要使用isChanged.postValue(!this)。
<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}" />

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