Соберите StateFlow в нескольких представленияхAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Соберите StateFlow в нескольких представлениях

Сообщение Anonymous »

У меня есть StateFlow, который я хотел бы собрать в двух разных представлениях: Activity и Fragment. Мне нужно обновить пользовательский интерфейс в действии и фрагменте с помощью одного и того же потока.
Использование по умолчанию asStateFlow() или asSharedFlow() не работает. Я читал о stateIn и ShareIn, которые, похоже, способны решить именно эту проблему. Я попробовал оба, но они не сработали. Вот пример stateIn. Я также попробовал ShareIn, и результаты были такими же. Я также попробовал SharingStarted.WhileSubscribed(), но опять же результаты были такими же. Что я делаю не так?
Согласно:
sealed class SearchStates {
class ConfigLoaded(val searchConfigList: List): SearchStates()
class Loading(val query: String): SearchStates()
}

Базовая модель представления:
// This ViewModel is extended by ActivityViewModel and FragmentViewModel
// hence the Activity and Fragment can access this flow
@HiltViewModel
open class BaseSearchViewModel() : ViewModel() {
private val _state: MutableStateFlow = MutableStateFlow(SearchStates.Started)
val state = _state.stateIn(viewModelScope, SharingStarted.Lazily, SearchStates.Started)
// ShareIn usage
// val state = _state.shareIn(viewModelScope, SharingStarted.WhileSubscribed())

fun onConfigLoadedd(configList: List) {
viewModelScope.launch {
_state.value = SearchStates.ConfigLoaded(configList)
}
}

fun onLoading(query: String) {
viewModelScope.launch {
_state.value = SearchStates.Loading(query)
}
}
}

Activity ViewModel, расширяющая BaseSearchViewModel:
@HiltViewModel
class SearchActivityViewModel @Inject constructor(

) : BaseSearchViewModel() {

fun onCreate() {
viewModelScope.launch {
listOf("1","2","3").let {
onConfigLoaded(it)
}
}
}

fun updateSearchQuery(query: String) {
viewModelScope.launch {
// Activity updates the state to Loading via BaseSearchViewModel
// I want to receive this new state in Activity and Fragment
onLoading(query)
}
}

Фрагмент ViewModel, расширяющий BaseSearchViewModel:
@HiltViewModel
class SearchFragmentViewModel @Inject constructor(

) : BaseSearchViewModel() {

}

Действие:
@AndroidEntryPoint
class SearchActivity : AppCompatActivity() {

private val viewModel: SearchActivityViewModel by viewModels()
private lateinit var binding: ActivitySearchBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySearchBinding.inflate(layoutInflater)
setContentView(binding.root)
bindViewActions()
observeViewModel()
viewModel.onCreate()
}

private fun bindViewActions() {
activityButton.setOnClickListener {
viewModel.updateSearchQuery("sleep")
}
}

private fun observeViewModel() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.state.collect {
when (it) {
is SearchStates.ConfigLoaded -> {
addFragments(it)
}

is SearchStates.Loading -> {
Log.d("TAG", "Activity Loading: ${it.query}")
}
}
}
}
}
}

private fun addFragments(configs: List) {
val fragmentTransaction = supportFragmentManager.beginTransaction()
configs.forEach { config ->
val fragment = SearchFragment()
fragmentsList.add(fragment)
fragmentTransaction.add(R.id.searchFragmentContainer, fragment)
}
fragmentTransaction.commit()
}
}

Фрагмент:
@AndroidEntryPoint
class SearchFragment : Fragment() {

private val viewModel: SearchFragmentViewModel by viewModels()
private lateinit var binding: FragmentSearchBinding

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = FragmentSearchBinding.inflate(inflater, container, false)
return binding.root
}

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

private fun observeViewModel() {
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.state.collect {
when (it) {
is SearchStates.Loading -> {
Log.d("TAG", "Fragment Loading: ${it.query}")
}
}
}
}
}
}
}

activity_search.xml:













fragment_search.xml:









Вывод Logcat:
2024-07-12 18:07:40.955 D Activity Loading: sleep

Ожидаемый результат Logcat:
2024-07-12 18:07:40.955 D Activity Loading: sleep
2024-07-12 18:07:40.955 D Fragment Loading: sleep


Подробнее здесь: https://stackoverflow.com/questions/787 ... iple-views
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»