user4383363
user4383363

Reputation:

Singleton Kotlin class extending RoomDatabase is called just once

I am using a Java codebase of an app to build another app in Kotlin. I've written a class AppDatabase extending RoomDatabase that is a singleton. It works once, and the other times the class isn't called. This is the class:

@Database(entities = [Classes::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
    abstract fun classesDao() : ClassesDao
}

object DatabaseProvider {
    private var database: String = "db_classes"
    private var sInstance: AppDatabase? = null

    fun getInstance(context: Context) : AppDatabase {
        if (sInstance == null) {
            sInstance = Room.databaseBuilder(
                context.applicationContext,
                AppDatabase::class.java,
                database
            ).build()
        }

        return sInstance!!
    }
}

My MainActivity displays a CalendarView that will fetch data by the selected date (so far it fetches after I pressed a date).

...
    ...
    mCalendar = findViewById(R.id.calendar)
    mCalendar?.setOnDateChangeListener { _, y, m, d ->
        mSelectedDate = DateUtils.convertToDate(y.toString(), m.toString(), d.toString())
        fetchClasses()
    }
    ...
...

private fun fetchClasses() {
    val modelFactory = MainViewModelFactory(this.applicationContext, mSelectedDate!!)
    val classesViewModel = ViewModelProviders.of(this, modelFactory).get(MainViewModel::class.java)

    classesViewModel.getClasses().observe(this, Observer<List<Classes>> {
        if (it!!.isEmpty()) {
            mRvClasses?.visibility = View.GONE
            mTvNoClasses?.visibility = View.VISIBLE
            mImgNoClasses?.visibility = View.VISIBLE
        }

        mAdapter?.setClasses(it)
    })
}

The MainViewModel:

class MainViewModel(context: Context, date: String) : ViewModel() {
    private var classes: LiveData<List<Classes>>?  = null
    private var db: AppDatabase? = null

    init {
        db = DatabaseProvider.getInstance(context)
        classes = db?.classesDao()?.getClassesByDate(date)
    }

    fun getClasses() : LiveData<List<Classes>> {
        return classes!!
    }
}

It works, but I noticed that if I switch the date, it will not be called anymore. If I, for example after the app opens select one date only, I can store as many records for that date as I want, but the moment I switch the date, it will stop being called and inserted.

This is the Java code I based on:

@Database(entities = { TaskEntry.class }, version = 1, exportSchema = false)
@TypeConverters(DateConverter.class)
public abstract class AppDatabase extends RoomDatabase {

    private static final Object LOCK = new Object();
    private static final String DATABASE_NAME = "todolist";
    private static AppDatabase sInstance;

    public static AppDatabase getInstance(Context context) {
        if (sInstance == null) {
            synchronized (LOCK) {
                sInstance = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, AppDatabase.DATABASE_NAME).build();
            }
        }

        return sInstance;
    }

    public abstract TaskDao taskDao();
}

Upvotes: 1

Views: 776

Answers (1)

Anatolii
Anatolii

Reputation: 14660

You should invoke a new SQL query when the date is modified. First, modify your ViewModel so that it reacts to Date changes:

class MainViewModel(context: Context, date: String) : ViewModel() {
    private var db: AppDatabase? = null
    private val dateInput = MutableLiveData<String>()
    val classes: LiveData<List<Classes>>

    init {
        db = DatabaseProvider.getInstance(context)
        dateInput.value = date
        classes = Transformations.switchMap(dateInput, {
            db?.classesDao()?.getClassesByDate(it)
        })
    }

    fun setDate(date: String) {
        dateInput.value = date
    }
}

Then, in your MainActivity onCreate(...) each time a Date changes just call classesViewModel.setDate(mSelectedDate). I removed fetchClasses() because there's no need to call each time but only in onCreate:

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    mCalendar = findViewById(R.id.calendar)
    mCalendar?.setOnDateChangeListener { _, y, m, d ->
        mSelectedDate = DateUtils.convertToDate(y.toString(), m.toString(), d.toString())
        // just update the date and nothing else is needed 
        classesViewModel.setDate(mSelectedDate)
    }
    val modelFactory = MainViewModelFactory(this.applicationContext, mSelectedDate)
    val classesViewModel = ViewModelProviders.of(this, modelFactory).get(MainViewModel::class.java)    
    classesViewModel.classes.observe(this, Observer<List<Classes>> {
        if (it!!.isEmpty()) {
            mRvClasses?.visibility = View.GONE
            mTvNoClasses?.visibility = View.VISIBLE
            mImgNoClasses?.visibility = View.VISIBLE
        }

        mAdapter?.setClasses(it)
    })
    ...
}

For more info please look here

Upvotes: 0

Related Questions