1

我正在做一个练习项目,我将订阅者存储在房间数据库中。我在 DAO 中使用流,稍后在视图模型中将它们作为状态流。这很好用,但是当我更新任何订阅者(更改他们的姓名或电子邮件)时,用户界面为什么没有反应。它仅在我插入或删除时更新。可能是什么问题呢?以这种方式使用 StateFlow 是否最佳?

(它适用于 LiveData,但我想尝试使用 StateFlows)

我感谢任何形式的帮助

视图模型:

class SubscriberViewModel(private val repository: SubscriberRepository) : ViewModel() {

private var isUpdateOrDelete = false
private lateinit var subscriberToUpdateOrDelete: Subscriber

val inputName = MutableStateFlow("")
val inputEmail = MutableStateFlow("")

private val _isDataAvailable = MutableStateFlow(false)
val isDataAvailable : StateFlow<Boolean>
    get() = _isDataAvailable

val saveOrUpdateButtonText = MutableStateFlow("Save")
val deleteOrDeleteAllButtonText = MutableStateFlow("Delete all")

private val _subscribers : MutableStateFlow<List<Subscriber>> = MutableStateFlow(emptyList())
    get() {
        viewModelScope.launch(Dispatchers.IO) {
            repository.subscribers.collect {
                field.value = it
            }
        }
        return field
    }

val subscribers : StateFlow<List<Subscriber>>
    get() = _subscribers



private fun clearInput() {
    inputName.value = ""
    inputEmail.value = ""
    isUpdateOrDelete = false
    saveOrUpdateButtonText.value = "Save"
    deleteOrDeleteAllButtonText.value = "Delete all"
}

fun initUpdateAndDelete(subscriber: Subscriber) {
    inputName.value = subscriber.name
    inputEmail.value = subscriber.email
    isUpdateOrDelete = true
    subscriberToUpdateOrDelete = subscriber
    saveOrUpdateButtonText.value = "Update"
    deleteOrDeleteAllButtonText.value = "Delete"
}

fun saveOrUpdate() {
    if (isUpdateOrDelete) {
        subscriberToUpdateOrDelete.name = inputName.value
        subscriberToUpdateOrDelete.email = inputEmail.value
        update(subscriberToUpdateOrDelete)
    } else {
        val name = inputName.value
        val email = inputEmail.value
        if (name.isNotBlank() && email.isNotBlank()) {
            insert(Subscriber(0, name, email))
        }
        inputName.value = ""
        inputEmail.value = ""
    }
}

fun deleteOrDeleteAll() {
    if (isUpdateOrDelete) {
        delete(subscriberToUpdateOrDelete)
    } else {
        deleteAll()
    }
}

private fun insert(subscriber: Subscriber) = viewModelScope.launch(Dispatchers.IO) {
    repository.insert(subscriber)
    //StateFlow changed, UI received the change
    _isDataAvailable.value = true
}

private fun update(subscriber: Subscriber) = viewModelScope.launch(Dispatchers.IO) {
    repository.update(subscriber)
    //StateFlow changed, UI can't receive the change
    clearInput()
}

private fun delete(subscriber: Subscriber) = viewModelScope.launch(Dispatchers.IO) {
    repository.delete(subscriber)
    //StateFlow changed, UI received the change
    clearInput()
}

private fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
    repository.deleteAll()
    //StateFlow changed, UI received the change
    _isDataAvailable.value = false
}
}

主要活动:

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: SubscriberViewModel
private lateinit var viewModelFactory: SubscriberViewModelFactory

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    val dao = SubscriberDatabase.getInstance(application).subscriberDAO
    viewModelFactory = SubscriberViewModelFactory(SubscriberRepository(dao))
    viewModel = ViewModelProvider(this, viewModelFactory)[SubscriberViewModel::class.java]
    binding.viewModel = viewModel
    binding.lifecycleOwner = this
    initRecycleView()
}

private fun initRecycleView() {
    binding.recyclerViewSubscribers.layoutManager = LinearLayoutManager(
        this@MainActivity,
        LinearLayoutManager.VERTICAL, false
    )
    displaySubscribersList()
}

private fun displaySubscribersList() {
    lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.STARTED) {
            viewModel.subscribers.collect { list -> //This code doesn't run when I update a subscriber
                binding.recyclerViewSubscribers.adapter = SubscriberRecyclerViewAdapter(list) {
                        subscriber: Subscriber -> listItemClicked(subscriber)
                }
            }
        }
    }
}

private fun listItemClicked(subscriber: Subscriber) {
    Toast.makeText(this, "${subscriber.name} is selected", Toast.LENGTH_SHORT).show()
    viewModel.initUpdateAndDelete(subscriber)
}

}
4

0 回答 0