代码之家  ›  专栏  ›  技术社区  ›  fermoga

扩展RoomDatabase的Singleton Kotlin类只调用一次

  •  1
  • fermoga  · 技术社区  · 6 年前

    我正在使用一个应用程序的Java代码库在Kotlin中构建另一个应用程序。我写了一个班 AppDatabase 延伸 RoomDatabase 那是一个单子。它只工作一次,其他时间类不被调用。这是班级:

    @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!!
        }
    }
    

    我的 MainActivity 显示 CalendarView 它将按选定的日期获取数据(到目前为止,它是在我按下日期之后获取的)。

    ...
        ...
        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)
        })
    }
    

    这个 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!!
        }
    }
    

    它工作,但我注意到,如果我切换日期,它将不再被调用。例如,如果我在应用程序打开后只选择一个日期,我可以存储该日期的任意多个记录,但当我切换日期时,它将停止被调用和插入。

    这是我基于的Java代码:

    @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();
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Anatolii    6 年前

    你应该调用一个新的 SQL 修改日期时查询。首先,修改 ViewModel 所以它会对 Date 变化:

    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
        }
    }
    

    然后,在你的 MainActivity onCreate(...) 每次 日期 改变只是打电话 classesViewModel.setDate(mSelectedDate) . 我删除了 fetchClasses() 因为没必要每次都打电话 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)
        })
        ...
    }
    

    更多信息请看 here