SharedFlow
LiveData
这里有一些代码
@AndroidEntryPoint
class FragmentA : Fragment() {
private val viewModel: ViewModelA by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = FragmentBinding.inflate(layoutInflater, container, false)
viewModel.state.observe(viewLifecycleOwner) {
it?.let {
binding.fragmentInt.text = it.toString()
}
}
binding.fragmentInt.setOnClickListener {
findNavController().navigate(
FragmentADirections.actionFragmentAToFragmentB()
)
}
return binding.root
}
}
@HiltViewModel
class ViewModelA @Inject constructor(
private val intRepository: IntRepository
) : ViewModel() {
private val _state: MutableLiveData<Int?> = MutableLiveData(null)
val state: LiveData<Int?> = _state
init {
viewModelScope.launch {
intRepository.observeScreenState().collect {
_state.value = it
}
}
intRepository.updateScreenState(1)
}
}
@AndroidEntryPoint
class FragmentB : Fragment(R.layout.fragment) {
private val viewModel: ViewModelB by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentBinding.inflate(layoutInflater, container, false)
viewModel.state.observe(viewLifecycleOwner) {
it?.let {
binding.fragmentInt.text = it.toString()
}
return binding.root
}
}
@HiltViewModel
class ViewModelB @Inject constructor(
private val intRepository: IntRepository
) : ViewModel() {
private val _state: MutableLiveData<Int?> = MutableLiveData(null)
val state: LiveData<Int?> = _state
init {
viewModelScope.launch {
intRepository.observeScreenState().collect {
_state.value = it
}
}
intRepository.updateScreenState(6)
}
}
class IntRepository @Inject constructor() {
private val screenStateFlow = MutableStateFlow<Int?>(null)
fun observeScreenState(): Flow<Int?> = screenStateFlow.asStateFlow()
fun updateScreenState(value: Int) {
screenStateFlow.value = value
}
}
update:
在广泛的测试和虚拟应用程序的支持之后,我注意到问题似乎是使用Hilt库。 没有它,我的流量完全按照我的期望工作,但是似乎添加DI库正在停止收集本应观察到的数据。 我已经更新了代码,以反映导致我得出这个结论的虚拟应用程序的状态。没有明确的答案就如何 - 或原因 - 爬行到底这样做。
如果您想再次回到其他屏幕并再次回来时,您想再次收听变量。
viewModelScope
您应该在下面的OnViewCreate中指定我在片段中指定的代码网关。
init {
viewModelScope.launch {
screenStateRepository.observeScreenStateFlow().collect {
_state.value = it
}
}
}
碎片;
fun testt() {
viewModelScope.launch {
screenStateRepository.observeScreenStateFlow().collect {
_state.value = it
}
}
}
您在存储库中的共享流正在使用默认的
将您的共享流量更改为具有一个
replay
或将其更改为状态流。也要查找
replay
shareIn
函数。他们会大量清理您的代码。例如,这可以执行您上面发布的代码所做的事情,同时还可以避免在视图模式不必要的情况下进行不必要的更新。
stateIn
// ViewModel A
...
private val state = screenStateRepository.observeScreenStateFlow()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), ScreenStateState())
注释,Hilt正在创建我的存储库的替代版本。
由于我是Hilt图书馆的新手,这完全笼罩在我的头上。 但是,经过数小时的调试,并将罪魁祸首缩小到注入的依赖性之后,快速重新阅读了匕首的剑柄文档 - 加上这里有一些有见地的评论的帮助 - 使我能够添加所需的注释的简单答案,例如确保我的存储库的正确行为。
由于您的代码非常抽象,我不太了解它。您应该清楚地写出它,因为处理流程中的代码非常复杂,易于误解。我从未使用过共享流,只有状态流。这是我通常所做的事情,您可以参考,希望能帮助您:
Repository
@Singleton
模型A
suspend fun setFrameCustom(frame : String) {
context.dataStore.edit {
it[FRAME_CUSTOM_DEFAULT] = frame
}
}
val frameDefault : Flow<String> = context.dataStore.data.catch {
exception -> if (exception is IOException) {
emit(emptyPreferences())
}
else {
emit(emptyPreferences()) throw exception
}
}.map{preference -> preference[FRAME_CUSTOM_DEFAULT] ?: ""}
companion object {
val FRAME_CUSTOM_DEFAULT = stringPreferencesKey("FRAME_CUSTOM_DEFAULT")
}
卸下模型
val frameDefaultFlow = repository.frameDefault