- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是学Android开发的,看到很多话题都说LiveData不推荐用了。我的意思是它不是最新的,我们应该改用 Flows。
我正在尝试使用 Flows 从 ROOM 数据库获取数据,然后将它们转换为 StateFlow,因为我知道它们是可观察的,而且我还想向它们添加 UI 状态。比如当我成功获取数据时,状态会变为 Success,如果失败,则变为 Error。
我有一个简单的练习应用程序。它存储订阅者的姓名和电子邮件,并在回收站 View 中显示它们。
我查了很多网站,如何使用stateIn方法,如何使用StateFlows和Flows但没有成功。执行此操作的最佳方法是什么?
还有什么是更新 recyclerview 适配器的正确方法?一直在MainActivity中换一个新的adapter可以吗?
这是项目(SubscriberViewModel.kt - 第 30 行): Project link
如果我做错了其他事情,请告诉我,我想学习。我感谢任何形式的帮助。
道:
import androidx.room.*
import kotlinx.coroutines.flow.Flow
@Dao
interface SubscriberDAO {
@Insert
suspend fun insertSubscriber(subscriber : Subscriber) : Long
@Update
suspend fun updateSubscriber(subscriber: Subscriber) : Int
@Delete
suspend fun deleteSubscriber(subscriber: Subscriber) : Int
@Query("DELETE FROM subscriber_data_table")
suspend fun deleteAll() : Int
@Query("SELECT * FROM subscriber_data_table")
fun getAllSubscribers() : Flow<List<Subscriber>>
@Query("SELECT * FROM subscriber_data_table WHERE :id=subscriber_id")
fun getSubscriberById(id : Int) : Flow<Subscriber>
}
View 模型:
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")
/*
//TODO - How to implement this as StateFlow<SubscriberListUiState> ??
//private val _subscribers : MutableStateFlow<SubscriberListUiState>
//val subscribers : StateFlow<SubscriberListUiState>
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)
_isDataAvailable.value = true
}
private fun update(subscriber: Subscriber) = viewModelScope.launch(Dispatchers.IO) {
repository.update(subscriber)
clearInput()
}
private fun delete(subscriber: Subscriber) = viewModelScope.launch(Dispatchers.IO) {
repository.delete(subscriber)
clearInput()
}
private fun deleteAll() = viewModelScope.launch(Dispatchers.IO) {
repository.deleteAll()
//_subscribers.value = SubscriberListUiState.Success(emptyList())
_isDataAvailable.value = false
}
sealed class SubscriberListUiState {
data class Success(val list : List<Subscriber>) : SubscriberListUiState()
data class Error(val msg : String) : SubscriberListUiState()
}
}
主要 Activity :
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 { uiState ->
when (uiState) {
is SubscriberViewModel.SubscriberListUiState.Success -> {
binding.recyclerViewSubscribers.adapter = SubscriberRecyclerViewAdapter(uiState.list) {
subscriber: Subscriber -> listItemClicked(subscriber)
}
}
is SubscriberViewModel.SubscriberListUiState.Error -> {
Toast.makeText(applicationContext,uiState.msg, Toast.LENGTH_LONG).show()
}
}
}
}
}*/
}
private fun listItemClicked(subscriber: Subscriber) {
Toast.makeText(this, "${subscriber.name} is selected", Toast.LENGTH_SHORT).show()
viewModel.initUpdateAndDelete(subscriber)
}
}
最佳答案
您可以使用 stateIn
方法将 Flow 类型转换为 StateFlow。
private val coroutineScope = CoroutineScope(Job())
private val flow: Flow<CustomType>
val stateFlow = flow.stateIn(scope = coroutineScope)
为了将 CustomType 转换为 UIState,您可以在 Flow
上使用 transformLatest
方法。它将类似于以下内容:
stateFlow.transformLatest { customType ->
customType.toUiState()
}
您可以在其中创建扩展函数以将 CustomType
转换为 UiState
,如下所示:
fun CustomType.toUiState() = UiState(
x = x,
y = y... and so on.
)
关于android - 如何将 Flow<CustomType> 转换为 StateFlow<UIState>? - 安卓 Kotlin ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70709121/
我为 Android 开发应用程序。我想知道我一次可以观察多少个 Kotlin Stateflow?每observe我所做的是在我自己创建的不同 CoroutineScope 上完成的,由 IO 调度
我正在使用 RecyclerView 并使用 Retrofit 从服务器获取数据。我正在使用 Kotlin 和 MVVM 设计模式。我使用过 LiveData,它运行良好。但是当我们导航到另一个 fr
在我的应用中,我有一个 UIState 密封类来表示 UI 状态。 sealed class UIState { class ShowLoading : UIState() class
我最近开始在 Android 中使用 Flows。我读到 Flows 很冷 StateFlows 很热,那么为什么我们更喜欢使用 Android 的 StateFlows 而不是 Flows?使用 F
我想使用 StateFlow。但是现在,我找不到任何可以帮助我的讲座。 我面临一个问题: 首先,我有一个包含字符串列表的单例,我想要一些“容易”理解的东西,即使它不是现在的目标。目的是用字符串填充和发
所以我正在更新我的RecylerView与 StateFlow如下所示: 我的数据类: data class Student(val name: String, var isSelected: Boo
我今天下载了 Android Studio Bumblebee 测试版并注意到一个新警告: “不应在组合中调用 StateFlow.value” 为什么我们不应该在组合中调用 StateFlow.va
我有一个登录表单。我用 StateFlow发送LoginResult (调用 API 后)来自 ViewModel至Activity .在 Activity 中,如果登录失败,我将显示一个错误对话框。
我在 Compose 和 MVVM 架构中开发该应用程序。我有 viewModel 与每个屏幕的 View 状态。 View 模型: class ProfileViewModel : ViewMode
考虑一个密封类状态。 sealed class State { object Unknown : State() object Loading : State() object
我正在这样创建 MutableStateFlow: val intSet = MutableStateFlow(HashSet()) 稍后我想更新此流程中的集合: intSet.value.add(0
我在 Compose 和 MVVM 架构中开发该应用程序。我有 viewModel 与每个屏幕的 View 状态。 View 模型: class ProfileViewModel : ViewMode
考虑一个密封类状态。 sealed class State { object Unknown : State() object Loading : State() object
我正在这样创建 MutableStateFlow: val intSet = MutableStateFlow(HashSet()) 稍后我想更新此流程中的集合: intSet.value.add(0
我有一个从设备传感器接收数据的类。我已将回调包装在 callbackFlow 中以获得 Flow。 private var sensorFlow: Flow = callbackFlow {
我们可以用类似下面的方式创建 LiveData 或 StateFlow val _liveData = MutableLiveData(0) val _stateFlow = MutableState
有函数collectAsState()适用于 StateFlow属性以便在 Composable 中观察它. 可组合项需要 StateFlow因为StateFlow保证初始值。 Flow没有这种保证。
正如我在标题中提到的,我很好奇两者之间的一般差异。你能帮忙吗?我找不到具体的区别,因为互联网上有复杂的例子。 在性能方面有什么区别? 在哪些场景下有优势? 将 StateFlow 与 Kotlin F
和 有什么区别?共享流 和 状态流 ? 以及如何在 中使用这些MVI 建筑学?使用简单 更好吗?流量 还是这些状态和事件? 最佳答案 Flow 很冷!,这意味着它仅在收集数据时才发出数据。 Flow
一定是一个非常简单的解决方案,但是......我在我的 android 项目中使用 StateFlow 来替换在服务中用作 Observables 的 LiveData。我使用 LiveData 作为
我是一名优秀的程序员,十分优秀!