Search code examples
androidkotlinandroid-room

How to update Room database in Android


In my application I want use MVI for application architecture and I should use Room database.
I have one activity and one fragment!
In fragment I receive data from user and save into database and in activity show this data into recyclerview.
I write below codes and my data successfully save into database!
But for show it into activity, I should exit from application and enter to show data list!
I want without exit from application, update automatically this list.
Dao codes :

@Query("SELECT * FROM my_table")
fun getAllData(): MutableList<Entity>

Repository codes:

class MyRepository @Inject constructor(private val dao: DataDao) {
    fun allData() = dao.getAllData()
}

ViewModel codes:

@HiltViewModel
class MyViewModel @Inject constructor(private val repository: MyRepository) : ViewModel() {
    val mainIntent = Channel<MainIntent>()
    private val _state = MutableStateFlow<MainState>(MainState.Idle)
    val state : StateFlow<MainState> get() = _state

    init {
        handleIntent()
    }

    private fun handleIntent() {
        viewModelScope.launch {
            mainIntent.consumeAsFlow().collect{
                when(it){
                    is MainIntent.LoadAllData-> fetchingAllDataList()
                }
            }
        }
    }

    private fun fetchingAllDataList() {
        viewModelScope.launch {
            _state.value = MainState.LoadData(repository.allData())
        }
    }
}

Activity codes :

lifecycleScope.launch {
    //Send
    viewModel.mainIntent.send(MainIntent.LoadAllData)
    //Get
    viewModel.state.collect { state ->
        when (state) {
            is MainState.Idle -> {}
            is MainState.LoadData -> {
                dataAdapter.setData(state.list)
                fataList.apply {
                    layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
                    adapter = noteAdapter
                }
            }
        }
    }
}

How can I fix this problem?


Solution

  • Several methods below can solve this problem.

    1. Use EventBus. Send an EventBus message after saving data to database in fragment and handle this message in MyViewModel or your Activity to reload data
    2. In your 'dao' interface, change function return type to LiveData: fun getAllData(): LiveData<MutableList<Entity>>. When related data changed in database, Room database automaticly notify changes to Observers. Check this
    3. Use Broadcast like using EventBus
    4. If fragment is contained in the Activity which requires the notification when data changed, use SharedViewModel to notify activity.
    class MyFragment: BottomDialogSheetFragment {
        var entityChangeListener: IEntityChangeListener? = null
        ...
        // after saving data to database
        entityChangeListener?.onChanged()
    }
    
    class MyActivity {
        fun showDialog() {
            val fragment = MyFragment()
            fragment.entityChangeListener = object : IEntityChangeListener {
                override fun onChanged() {
                    // change [fetchAllDataList] function to public
                    myViewModel.fetchAllDataList()
                }
            }
        }
    }
    
    interface IEntityChangeListener {
        fun onChanged()
    }
    
    // using SharedViewModel
    class MyFragment: BottomDialogSheetFragment {
        var entityViewModel by sharedViewModel<EntityViewModel>
        ...
        // saving entity data
        entityViewModel.saveData(entities)
    }
    
    class MyActivity {
        // shared view model for entity database business
        val entityViewModel by viewModels<EntityViewModel>
        // viewmodel for other business logic
        val viewModel by viewModels<MyViewModel>
    
    }
    
    class EntityViewModel: ViewModel(){
        ...
        private val _state = MutableStateFlow<MainState>(MainState.Idle)
        val state : StateFlow<MainState> get() = _state
    
        fun fetchingAllDataList() {
            viewModelScope.launch(Dispatchers.IO) {
                _state.value = MainState.LoadData(repository.allData())
            }
        }
    
        fun saveData(entities: List<Entity>) {
            dao.save(entities)
            fetchingAllDataList()
        }
    }