带有LiveData的会议室:适配器中的多对多映射

时间:2018-07-31 21:38:41

标签: android kotlin android-room android-livedata

让我们举一个例子:

PRODUCTS和ORDERS存在许多映射。因此,一个产品可以有多个订单,一个订单可以有多个产品。在会议室中,我有一个实体,该实体同时具有产品ID和订单ID作为外键,因此可以保存关系。现在,很容易获得特定产品的所有订单以及特定订单的所有产品。

现在麻烦来了。据我所知,没有办法在1个查询/实体中获取所有产品的订单对象。可以更详细地了解这一点in this post.,在大多数地方,我可以通过运行两个查询来绕过它。第一个获取我感兴趣的订单,第二个基于订单的ID获取产品。

现在,我想在适配器中显示订单及其产品的组合。为此,我需要将所有订单与其产品组合起来。我对如何使用LiveData解决这个问题一无所知。

我认为最好的解决方案是创建一个直接从数据库中获取OrderWithProducts的查询。 This post suggests应该有可能,但是我还没有设法使它生效。同样,该示例中最关键的部分缺失:OrderItem类。

如果无法实现该解决方案,则必须采用某种方法来获取带有2个查询的LiveData OrderWithProducts列表,并以某种方式将其合并。

编辑 根据@Demigod的建议,现在在ViewModel中有以下内容:

// MediatorLiveData can observe other LiveData objects and react on their emissions.
var liveGroupWithLights = MutableLiveData<List<GroupWithLights>>()

fun createOrdersWithProducts() {
        appExecutors.diskIO().execute {
            val ordersWithProducts = mutableListOf<OrderWithProducts>()
            val orders = orderRepository.getGroupsSync()
            for (order in orders) {
                val products = productRepository.getProductsSync(order.id)
                val orderWithProducts = OrderWithProducts(order, products)
                ordersWithProducts.add(orderWithProducts)
            }

            liveGroupWithLights.postValue(ordersWithProducts)
        }
    }

我片段中的用于向适配器提交数据的函数:

private fun initRecyclerView() {
    orderListViewModel.getOrdersWithProducts().observe(this, Observer { result ->
        adapter.submitList(result)
    })
}

因此,现在我可以将OrderWithProduct对象用作适配器的项目。太好了,我可以在适配器中为每个订单使用产品。现在,每当数据库中的值更改时,我都无法更新这些项目。这部分有什么想法吗?

Edit2:invalidationtracker

db.invalidationTracker.addObserver(object : InvalidationTracker.Observer("orders", "products", "order_product_join") {
        override fun onInvalidated(tables: MutableSet<String>) {
            createOrdersWithProducts()
        }
    })

我现在遇到的问题是,对于单个更改,验证跟踪器会收到很多通知。

1 个答案:

答案 0 :(得分:0)

据我所知,目前无法使用单个查询。 为了解决这个问题,您将需要在此处运行几个查询。首先-通过单个查询获取订单列表,然后再获取每个订单的产品列表。为此,我可以考虑几种选择:

  1. 制作自己的OrdersWithProductsProvider,它将返回此组合的实体(OrderList<Porduct>),并且它将订阅对database的更改以使用发出新对象每个LiveDataorders表更改中的products
  2. 您可以使用MediatorLiveData用它们的Order来填充Product的列表,但是我认为这不是最好的方法,因为您将需要运行查询在后台线程中,也许在这里使用Rx更方便。

我个人会使用第一个选项,因为我可能想获取有关其产品的最新订单清单,这意味着更新应在三个表(products,{ {1}},orders),可以通过products_to_orders完成。在该提供程序内部,我将使用Room.InvalidationTracker(可以通过RxLiveData一起使用)。

有关如何实现此目标的附加信息:

如何实现这一点并不重要,唯一的事情是-在后台线程中运行整个查询,并将其发布到LiveDataReactiveStreams。您可以使用LiveDataExecutor或简单的Rx。所以它看起来像:

Thread

将其视为不是完整的工作代码,而是实现的示例。 在初始化/首次调用时调用private val database : Database // Get the DB private val executor = Executors.newSingleThreadExecutor() private val liveData = MutableLiveData<List<OrderWithProducts>>() fun observeOrdersWithProducts():LiveData<List<OrderWithProducts>> { return liveData } private fun updateOrdersWithProducts() { executor.post { val ordersWithProducts = mutableListOf<OrderWithProducts>() val orders = db.orders() for (order : orders) { val products = database.productsForOrder(order) val orderWithProducts = OrderWithProducts(order, products) ordersWithProducts.add(orderWithProducts) } liveData.post(ordersWithProducts) } } ,每次updateOrdersWithProducts都会通知数据库更改。