Search code examples
androidkotlinkotlin-coroutineskotlin-stateflow

ListAdapter is not being notified whenever data is updated and emitted by StateFlow


StateFlow is emitting new data after change, but ListAdapter is not being updated/notified, but when configuration is changed(i.e device is rotated from Portrait to Landscape mode) update is occurred:

class TutorialListFragment : Fragment() {
    
        private lateinit var binding: FragmentTutorialListBinding
    
        private val viewModel: ITutorialViewModel by viewModels<TutorialViewModelImpl>()
        private lateinit var adapter: TutorialAdapter
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {
    
            binding = FragmentTutorialListBinding.inflate(inflater, container, false)
            return binding.root
    
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            val recyclerView = binding.recyclerView
    
            adapter = TutorialAdapter()
            recyclerView.adapter = adapter    
     
            loadData()   
    
        }
    
        private fun loadData() {
            viewModel
                .getTutorialList()
    
            val tutorialList: MutableList<TutorialResponse> = mutableListOf()

            viewModel
                .tutorialListStateFlow
                .onEach { list ->
                    list.forEach {tutorialResponse->
                        tutorialList.add(tutorialResponse)                       
                        Log.e("TUTORIAL_LIST_FRAG", "$tutorialResponse")
                    }
                    adapter.submitList(tutorialList)
                }.launchIn(viewLifecycleOwner.lifecycleScope)
        }
}

View model is:

class TutorialViewModelImpl: ViewModel(), ITutorialViewModel {

    private val mTutorialRepository: ITutorialRepository = TutorialRepositoryImpl()

    private val _tutorialListStateFlow = MutableStateFlow<List<TutorialResponse>>(mutableListOf())
    override val tutorialListStateFlow: StateFlow<List<TutorialResponse>>
        get() = _tutorialListStateFlow.asStateFlow()

    init {
        mTutorialRepository
            .getTutorialListSuccessListener {
                viewModelScope
                    .launch {
                        _tutorialListStateFlow.emit(it)
                        Log.e("TUTORIAL_GL_VM", "$it")
                    }
            }    
       
    }

    override fun getTutorialList() {
        // Get list
        mTutorialRepository.getTutorialList()
    }
}

When I look into Logcat I see this line:

Log.e("TUTORIAL_GL_VM", "$it")

prints all the changes, but no update in ListAdapter.


Solution

  • I assume your data from mTutorialRepository is not a flow ,so you must add .toList() if you want to emit list in stateFlow to get notified

    
    mTutorialRepository.getTutorialListSuccessListener {
       viewModelScope.launch {
          // here add .toList()
          _tutorialListStateFlow.emit(it.toList())             
       }
    } 
    
    

    or if it still does not works, try to change your loadData() like this

    
    private fun loadData() {
    // idk what are doing with this ??
    viewModel.getTutorialList()
    
    lifecycleScope.launch {
         viewModel.tutorialListStateFlow.collect { list ->
           adapter.submitList(list)
        }
      }
    }