通过UseCase观察Room数据库Flow时数据更新不发射的问题排查
核心问题:通过UseCase获取Room Flow时,数据更新不触发Flow发射
在采用Clean Architecture、MVVM架构的Android笔记应用中,使用Dagger Hilt实现依赖注入,结合Room数据库与Flow做数据监听。遇到如下问题:
- 直接调用Repository暴露的Flow时,向数据库添加笔记后,Flow会正常发射包含新笔记的列表;
- 通过UseCase封装相同逻辑后,笔记虽成功存入数据库,但获取笔记的Flow不会发射数据更新。
相关代码实现
NotesDao
@Dao interface NotesDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun addNote(noteEntity: NoteEntity) @Update suspend fun update(noteEntity: NoteEntity) @Delete suspend fun delete(noteEntity: NoteEntity) @Query("SELECT * FROM notes WHERE (:query IS NULL OR :query = '' OR LOWER(title) LIKE '%' || LOWER(:query) || '%' OR LOWER(content) LIKE '%' || LOWER(:query) || '%')") fun getNotesFlow(query: String? = null): Flow<List<NoteEntity>> }
LocalNotesDataSourceImpl
class LocalNotesDataSourceImpl( private val notesDao: NotesDao ) : LocalNotesDataSource { override suspend fun addNote(note: Note) { notesDao.addNote(note.toNoteEntity()) } override suspend fun updateNote(note: Note) { notesDao.update(note.toNoteEntity()) } override suspend fun deleteNote(note: Note) { notesDao.delete(note.toNoteEntity()) } override fun getNotesFlow(query: String?): Flow<List<Note>> { return notesDao.getNotesFlow(query) .map { notes -> notes.map { it.toNote() } } } }
NotesRepositoryImpl
class NotesRepositoryImpl( private val localNotesDataSource: LocalNotesDataSource ) : NotesRepository { override suspend fun addNote(note: Note) { localNotesDataSource.addNote(note) } override suspend fun deleteNote(note: Note) { localNotesDataSource.deleteNote(note) } override fun getNotesFlow(query: String?): Flow<List<Note>> { return localNotesDataSource.getNotesFlow(query) } }
UseCase实现
class GetNotesFlowUseCase( private val notesRepository: NotesRepository ) { fun invoke(query: String? = null) = notesRepository.getNotesFlow(query) } class AddNoteUseCase( private val notesRepository: NotesRepository ) { suspend fun invoke(note: Note) = notesRepository.addNote(note) }
UseCase依赖注入配置
@Module @InstallIn(SingletonComponent::class) object UseCaseModule { @Provides fun provideGetNotesFlowUseCase(notesRepository: NotesRepository): GetNotesFlowUseCase = GetNotesFlowUseCase(notesRepository) @Provides fun provideAddNoteFlowUseCase(notesRepository: NotesRepository): AddNoteUseCase = AddNoteUseCase(notesRepository) }
UI层代码
NotesListViewModel
@HiltViewModel class NotesListViewModel @Inject constructor( private val getNotesFlowUseCase: GetNotesFlowUseCase, private val addNoteUseCase: AddNoteUseCase, ) : ViewModel() { private val _uiState = MutableStateFlow(NoteListUiState()) val uiState = _uiState.asStateFlow() init { observeNotesFlow() } private fun observeNotesFlow() { viewModelScope.launch { // 此处直接调用notesRepository.getNotesFlow(query)可正常工作 getNotesFlowUseCase.invoke().collect { notes -> _uiState.value = _uiState.value.copy( notes = notes.map { it.toNoteItemUi() }, isLoading = false ) } } } fun addNote() { viewModelScope.launch { // 此处直接调用notesRepository.addNote(note)可正常工作 addNoteUseCase.invoke( Note( id = UUID.randomUUID(), title = "Title", content = "Content", timestamp = System.currentTimeMillis(), isInTrash = false, isArchived = false ) ) } } }
NotesListFragment
@AndroidEntryPoint class NotesListFragment : BaseFragment<FragmentNotesListBinding>() { override val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> FragmentNotesListBinding = FragmentNotesListBinding::inflate private val viewModel: NotesListViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.uiState .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) .onEach { uiState -> Timber.tag("NOTES FLOW").d(uiState.notes.toString()) } .launchIn(lifecycleScope) binding.fabAddNote.setOnClickListener { viewModel.addNote() } } }
目前的核心疑问:通过UseCase调用添加笔记后,笔记已成功存入数据库,但获取笔记的Flow未发射更新;直接调用Repository则一切正常。请问我的UseCase实现哪里出现了问题?
内容的提问来源于stack exchange,提问作者Tomasz Testowy
相关产品推荐
相关产品推荐

