У меня есть 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
Соберите StateFlow в нескольких представлениях ⇐ Android
Форум для тех, кто программирует под Android
-
Anonymous
1721009509
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
Подробнее здесь: [url]https://stackoverflow.com/questions/78739319/collect-stateflow-in-multiple-views[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия