Reputation: 51
I'm trying to observe changes in DB made from another fragment.
I have a fragment A (contains a recyclerView with items) with a ViewModel that has inside a LiveData property from the Room database.
Like this:
val allItems: LiveData<List <Item>> = repo.getAll()
If I open a new fragment (let's call it B) from fragment A and do repo.insert(item)
there, I expect the LiveData's observer to fire on allItems
when returning back to fragment A. But that doesn't happen.
How a can fix it nicely?
Of course I can get data in onViewCreated()
every time I open the fragment A, but I believe there must be a better way.
class CharactersViewModel : BaseViewModel() {
private val db get() = AppDatabase.getDB(MyApplication.application)
private val repo = CharacterRepository(viewModelScope, db.characterDao())
val characters: LiveData<List<Character>> = repo.getAll()
}
class CharacterRepository(
private val scope: CoroutineScope,
private val dao: CharacterDao
) {
fun getAll() = dao.getAll()
fun getById(itemId: Int) = dao.getById(itemId)
fun insert(item: Character) = scope.launch {
dao.insert(item)
}
fun update(item: Character) = scope.launch {
dao.update(item)
}
fun delete(item: Character) = scope.launch {
dao.delete(item)
}
}
@Dao
interface CharacterDao {
fun getAll(): LiveData<List<Character>>
fun getById(itemId: Int) : LiveData<Character>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(item: Character)
@Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun update(item: Character)
@Delete
suspend fun delete(item: Character)
}
Note: It looks like this is because the ViewModel of Fragment A is currently inactive. And the issue is not due to viewLifecycleOwner, since the observeForever is also not notified.
Upd: Just found the issue, answer attached.
Upvotes: 1
Views: 150
Reputation: 51
There was when getting the database instance.
fun getDB(appContext: Context) = Room.databaseBuilder(
appContext,
AppDatabase::class.java, DB_NAME
).build()
I solved the problem by making it a singleton, so now it returns the same instance of the DB.
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
@Synchronized
fun getDB(context: Context): AppDatabase {
// if the INSTANCE is not null, then return it, otherwise create the database
return INSTANCE ?: run {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
DB_NAME
).build()
INSTANCE = instance
instance
}
}
}
Upvotes: 2