扩展RoomDatabase的Singleton Kotlin类仅被调用一次

时间:2018-08-05 14:17:06

标签: android kotlin android-room

我正在使用一个应用程序的Java代码库在Kotlin中构建另一个应用程序。我编写了一个扩展2018-08-05T13:24:25.684757+00:00 heroku[router]: at=error code=H20 desc="App boot timeout" method=GET path="/favicon.ico" host=shallwetravel.herokuapp.com request_id=0fcb1900-b817-4073-b89f- 6e9f59733964 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=http 2018-08-05T13:24:25.753806+00:00 heroku[router]: at=error code=H20 desc="App boot timeout" method=GET path="/" host=shallwetravel.herokuapp.com request_id=f0156fe1-0bdf-4a8a-a899- e902f4665227 fwd="183.156.162.189" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:27.735346+00:00 heroku[router]: at=error code=H20 desc="App boot timeout" method=GET path="/" host=shallwetravel.herokuapp.com request_id=ecb40cae-bac1-4471-a451-960434d5c7b8 fwd="171.36.142.123" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:36.166718+00:00 heroku[router]: at=error code=H20 desc="App boot timeout" method=GET path="/view/img/favicon.ico" host=shallwetravel.herokuapp.com request_id=faf85879-730d-40e7-8db8- fafec7a5d104 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=http 2018-08-05T13:24:44.205137+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch 2018-08-05T13:24:44.205293+00:00 heroku[web.1]: Stopping process with SIGKILL 2018-08-05T13:24:44.296644+00:00 heroku[web.1]: Process exited with status 137 2018-08-05T13:24:44.320270+00:00 heroku[web.1]: State changed from starting to crashed 2018-08-05T13:24:45.115828+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=shallwetravel.herokuapp.com request_id=4b17ebd1-36a0-4a17-93ed-471613f07835 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=http 2018-08-05T13:24:45.157014+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/view/img/favicon.ico" host=shallwetravel.herokuapp.com request_id=256e1d40-c8c8-459b-af78- 0d5646db0989 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:45.079904+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/home/favicon.ico" host=shallwetravel.herokuapp.com request_id=a07bdfc2-3bbc-4149-bbde- 9ad0623be9dc fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:45.279417+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/2/favicon.ico" host=shallwetravel.herokuapp.com request_id=7b175312-f182-4869-8147- dce94c590483 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=http 2018-08-05T13:24:46.673153+00:00 heroku[router]: at=error code=H20 desc="App boot timeout" method=GET path="/home/favicon.ico" host=shallwetravel.herokuapp.com request_id=d7b91daa-63ce-436b-bd92- 99a241b68704 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=http 2018-08-05T13:24:46.731281+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/3/favicon.ico" host=shallwetravel.herokuapp.com request_id=68f1af4b-53cb-4987-b40c- 49d49cf703d5 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=http 2018-08-05T13:24:46.711881+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/2/favicon.ico" host=shallwetravel.herokuapp.com request_id=8e023a9b-08a0-4524-b877- 54c7e6a03e12 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:47.153652+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=shallwetravel.herokuapp.com request_id=4324f9b6-ffa2-4e02-b705- 3eb1a5e11bd0 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:47.455997+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=shallwetravel.herokuapp.com request_id=d999e2ef-c54e-49b6-8b74-fd186992d314 fwd="183.156.162.189" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:47.998079+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/3/favicon.ico" host=shallwetravel.herokuapp.com request_id=5a45cc93-8c0d-4da2-864d- e0b1fa6e9e7e fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:49.633746+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=shallwetravel.herokuapp.com request_id=20ed2c6b-290d-42ca-87ee- 0754ed92377d fwd="183.156.162.189" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:24:49.300596+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=shallwetravel.herokuapp.com request_id=07a88c91-9e1b-4b0d-87c1-878c1ba08d64 fwd="123.160.172.60" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:25:06.659632+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=shallwetravel.herokuapp.com request_id=610586c5-95a3-42f4-a318-985f489afece fwd="183.156.162.189" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:25:07.422356+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=shallwetravel.herokuapp.com request_id=cb3f9a81-74f8-481c-84e3- aa63d772f530 fwd="183.156.162.189" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:30:08.835326+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=shallwetravel.herokuapp.com request_id=5d106640-82f1-4b88-99a8-5f21861a620d fwd="183.156.162.189" dyno= connect= service= status=503 bytes= protocol=https 2018-08-05T13:30:10.004506+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=shallwetravel.herokuapp.com request_id=c135a334-eaeb-4a41-b186- 4d111289843a fwd="183.156.162.189" dyno= connect= service= status=503 bytes= protocol=https 的类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 个答案:

答案 0 :(得分:1)

修改日期后,您应该调用一个新的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(...) Date中,只需调用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