有两个数据库 'tables'、'foreign key' 和 'live data' 的房间
Room with two database 'tables', 'foreign key' and 'live data'
正在尝试创建两个相关 table 一对一的房间数据库。通过外键连接工作,但我发现很难用实时数据获取数据,我不知道这是否正确获取数据。
class GraphFragment : Fragment() {
private lateinit var graphVM: GraphVM
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_graph, container, false)
graphVM = ViewModelProviders.of(this).get(GraphVM::class.java)
graphVM.graphFiles.observe(this, Observer<List<GraphEntity>> {
it?.let {
graphVM.getDataFiles( it.map { it.fileID })
}
})
graphVM.dataFiles.observe(this, Observer<List<FileEntity>> {
it?.let {
// work with FileEntity
}
})
}
视图模型
class GraphVM(application: Application) : AndroidViewModel(application) {
private var graphFilesRepository: GraphRepository = GraphRepository(application)
private var fileRepository: FileRepository = FileRepository(application)
var graphFiles: LiveData<List<GraphEntity>> = MutableLiveData()
private set
var dataFiles: LiveData<List<FileEntity>> = MutableLiveData()
private set
init {
// this work
graphFiles = graphFilesRepository.getAllFiles()
}
fun getDataFiles(listOfFileIDs: List<Long?>) {
// this not
dataFiles = fileRepository.getFilesDataByID(listOfFileIDs)
}
}
文件存储库
class FileRepository(application: Application) {
private var fileDao: FileDao
init {
val database: FileDatabase = FileDatabase.getInstance(application)!!
fileDao = database.fileDao()
}
/..
../
fun getFilesDataByID(listOfFileIDs: List<Long?>): LiveData<List<FileEntity>> {
return fileDao.queryFilesEntityByID(listOfFileIDs)
}
}
道
@Dao
interface FileDao {
/..
../
@Query("SELECT * FROM file_data WHERE id IN (:listOfFileIDs)")
fun queryFilesEntityByID(listOfFileIDs : List<Long?>): LiveData<List<FileEntity>>
}
因此,当我在 init 中进行赋值时,实时数据会正确触发,但是当我尝试:
graphVM.getDataFiles( it.map { it.fileID })
Livedata是赋值,不触发。我知道这是正确的分配,因为当我删除时,从 FileRepository 更改值,livedata recive onChange 并且通知 observer。我想知道有什么办法可以解决这个问题,所以我可以在分配时使用 livedata 从房间数据库接收值。
@PS 找到问题了。当我尝试在 Observer{...} 中获取数据文件时,它不起作用,但是当我从 onCreateView{...} 调用函数时,它起作用了。
有什么解决办法吗?
这里的主要问题是您需要观察和更新 LiveData
的一个实例,但是 getDataFiles()
的调用会覆盖 dataFiles
字段。
首选解决方案是向客户端提供请求LiveData
并在客户端观察更新:
class GraphVM(application: Application) : AndroidViewModel(application) {
//...
fun getDataFiles(listOfFileIDs: List<Long?>): LiveData<List<FileEntity>> {
return fileRepository.getFilesDataByID(listOfFileIDs)
}
}
如果这种方式不合适,可以使用MediatorLiveData
切换数据源:
class GraphVM(application: Application) : AndroidViewModel(application) {
private var fileRepository: FileRepository = FileRepository(application)
private val dataFiles = MediatorLiveData<List<FileEntity>>()
private var request: LiveData<List<FileEntity>>? = null
// expose dataFiles as LiveData
fun getDataFiles(): LiveData<List<FileEntity>> = dataFiles
@MainThread
fun getDataFiles(listOfFileIDs: List<Long?>) {
// create new request to repository
val newRequest = fileRepository.getFilesDataByID(listOfFileIDs)
val observer = Observer<List<FileEntity>> { list ->
// remove previous subscription
request?.run { dataFiles.removeSource(this) }
// setup fresh data
dataFiles.value = list
// remember last request
request = newRequest
}
// register new observable data source (LiveData)
dataFiles.addSource(newRequest, observer)
}
}
正在尝试创建两个相关 table 一对一的房间数据库。通过外键连接工作,但我发现很难用实时数据获取数据,我不知道这是否正确获取数据。
class GraphFragment : Fragment() {
private lateinit var graphVM: GraphVM
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_graph, container, false)
graphVM = ViewModelProviders.of(this).get(GraphVM::class.java)
graphVM.graphFiles.observe(this, Observer<List<GraphEntity>> {
it?.let {
graphVM.getDataFiles( it.map { it.fileID })
}
})
graphVM.dataFiles.observe(this, Observer<List<FileEntity>> {
it?.let {
// work with FileEntity
}
})
}
视图模型
class GraphVM(application: Application) : AndroidViewModel(application) {
private var graphFilesRepository: GraphRepository = GraphRepository(application)
private var fileRepository: FileRepository = FileRepository(application)
var graphFiles: LiveData<List<GraphEntity>> = MutableLiveData()
private set
var dataFiles: LiveData<List<FileEntity>> = MutableLiveData()
private set
init {
// this work
graphFiles = graphFilesRepository.getAllFiles()
}
fun getDataFiles(listOfFileIDs: List<Long?>) {
// this not
dataFiles = fileRepository.getFilesDataByID(listOfFileIDs)
}
}
文件存储库
class FileRepository(application: Application) {
private var fileDao: FileDao
init {
val database: FileDatabase = FileDatabase.getInstance(application)!!
fileDao = database.fileDao()
}
/..
../
fun getFilesDataByID(listOfFileIDs: List<Long?>): LiveData<List<FileEntity>> {
return fileDao.queryFilesEntityByID(listOfFileIDs)
}
}
道
@Dao
interface FileDao {
/..
../
@Query("SELECT * FROM file_data WHERE id IN (:listOfFileIDs)")
fun queryFilesEntityByID(listOfFileIDs : List<Long?>): LiveData<List<FileEntity>>
}
因此,当我在 init 中进行赋值时,实时数据会正确触发,但是当我尝试:
graphVM.getDataFiles( it.map { it.fileID })
Livedata是赋值,不触发。我知道这是正确的分配,因为当我删除时,从 FileRepository 更改值,livedata recive onChange 并且通知 observer。我想知道有什么办法可以解决这个问题,所以我可以在分配时使用 livedata 从房间数据库接收值。
@PS 找到问题了。当我尝试在 Observer{...} 中获取数据文件时,它不起作用,但是当我从 onCreateView{...} 调用函数时,它起作用了。 有什么解决办法吗?
这里的主要问题是您需要观察和更新 LiveData
的一个实例,但是 getDataFiles()
的调用会覆盖 dataFiles
字段。
首选解决方案是向客户端提供请求LiveData
并在客户端观察更新:
class GraphVM(application: Application) : AndroidViewModel(application) {
//...
fun getDataFiles(listOfFileIDs: List<Long?>): LiveData<List<FileEntity>> {
return fileRepository.getFilesDataByID(listOfFileIDs)
}
}
如果这种方式不合适,可以使用MediatorLiveData
切换数据源:
class GraphVM(application: Application) : AndroidViewModel(application) {
private var fileRepository: FileRepository = FileRepository(application)
private val dataFiles = MediatorLiveData<List<FileEntity>>()
private var request: LiveData<List<FileEntity>>? = null
// expose dataFiles as LiveData
fun getDataFiles(): LiveData<List<FileEntity>> = dataFiles
@MainThread
fun getDataFiles(listOfFileIDs: List<Long?>) {
// create new request to repository
val newRequest = fileRepository.getFilesDataByID(listOfFileIDs)
val observer = Observer<List<FileEntity>> { list ->
// remove previous subscription
request?.run { dataFiles.removeSource(this) }
// setup fresh data
dataFiles.value = list
// remember last request
request = newRequest
}
// register new observable data source (LiveData)
dataFiles.addSource(newRequest, observer)
}
}