在Android Studio中的双向数据绑定中更改LiveData <MVoice>时,如何重置LiveData <Boolean>?

问题描述

EditText 使用双向数据绑定,而 Button 使用 layout_detail.xml

中的单向数据绑定

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

当EditText的内容更改时,aMVoiceDetailViewModel的值也将更改,我想我可以重置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 = "",)

解决方法

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

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

然后在布局中使用voiceNamevoicePath etc

<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'
,

那样尝试

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
            }
        }
    }
}

并从您有lifecycle owner的位置呼叫监听器-例如来自Fragment

class Fragment1 : Fragment() {

    lateinit var viewModel: DetailViewModel

    override fun onViewCreated(view: View,savedInstanceState: Bundle?) {
        super.onViewCreated(view,savedInstanceState)
        viewModel.listenChanges(viewLifecycleOwner)
    }

}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...