有两个数据库 '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)
    }
}