[英]How do I notify multiple Activities and Fragments of a dataset change?
Consider an Android app that displays lists of data and lets the user drill down into it. 考虑一个显示数据列表并允许用户向下钻取的Android应用。 At some point the user makes a change to the data that needs to be reflected in more than one Activity on the back stack.
在某些时候,用户对需要在后台堆栈上的多个活动中反映的数据进行更改。 What is the best pattern for achieving this?
实现此目标的最佳模式是什么?
There is a data source in your app. 您的应用中有一个数据源。 And its updates needs to reflect to multiple UI,
其更新需要反映到多个用户界面,
You need to somehow create a single source of truth for all the UI and reflect the changes to them when something happens. 您需要以某种方式为所有UI创建真实的来源,并在发生某些情况时将更改反映给他们。
I solved this problem in my project by using MVVM
and ViewModel
+ LiveData
from google's new architecture component. 我通过使用
MVVM
和来自Google新架构组件的ViewModel
+ LiveData
解决了这个问题。 Why? 为什么? Because they are life cycle aware!
因为他们知道生命周期! You can use RxJava to do the same thing.
您可以使用RxJava做同样的事情。
model layer
model layer
It's a singleton, and expose the data source as a LiveData
A. In the following code, it will be OrderLiveStore.liveData
. 这是一个单例,并将数据源公开为
LiveData
。在以下代码中,它将为OrderLiveStore.liveData
。
class OrderLiveStore(
private val orderStore: OrderStore
) {
var liveData: MutableLiveData<List<Order>> = MutableLiveData()
init {
liveData.value = orderStore.items
}
}
view model layer
: view model layer
: case 1: You just inject that model to the view model, and expose the LiveData
A to the view. 情况1:您只需将该模型注入视图模型,然后将
LiveData
A暴露给视图。 Underneath considering the fact of singleton, all views which connect to this view model will get the update, because the view model simply just returns the same property from a singleton variable. 在考虑单例事实的情况下,连接到该视图模型的所有视图都将获得更新,因为视图模型仅从单例变量中返回相同的属性。 I manage the singleton by using
dagger
. 我使用
dagger
管理单例。
class OrdersViewModel @Inject constructor( orderLiveStore: OrderLiveStore ): ViewModel() { // expose to the view directly val orders: LiveData<List<Order>> = orderLiveStore.liveData }
case 2: You still inject the model to the view model, but inside, you need to subscribe to it using Transformations.map
, and do your processing, and expose the result to the view layer 情况2:您仍然将模型注入视图模型,但是在内部,您需要使用
Transformations.map
对其进行订阅并进行处理,然后将结果公开给视图层
class OrderViewModel( orderLiveStore: OrderLiveStore, private val orderId: String ) : ViewModel() { // expose to the view after processing it val order: LiveData<Order> = Transformations.map(orderLiveStore.liveData) { getNeededOrderFromList(it) } private fun getNeededOrderFromList(orderList: List<Order>?): Order? { // This method will be triggered every time orderStore.liveData gets updated } }
You can see that in case 1, I use dagger to inject because it fits the case. 您可以看到,在情况1中,我使用匕首进行注入,因为它适合情况。 In case 2, I created the view model in view with custom parameter, because the view model needs some extra information to grab the needed pieces from the model layer.
在案例2中,我使用自定义参数在视图中创建了视图模型,因为视图模型需要一些额外的信息来从模型层获取所需的片段。 In my case, it is a
orderId:String
就我而言,这是一个
orderId:String
view layer
view layer
Now it's simple, be it a fragment or an activity, you observe that data source and update your UI, 现在很简单,无论是片段还是活动,您都可以观察到该数据源并更新UI,
orderViewModel.orders.observe(this, Observer {
// update the ui
})
or more elegantly, you can bind the LiveData
from view model directly to the xml
with data binding if you don't need that much pre-processing. 或更优雅地说,如果不需要太多预处理,则可以使用数据绑定将
LiveData
从视图模型直接绑定到xml
。
Well, you just update the model
layer DIRECTLY. 好吧,您只需直接更新
model
层。 But the action will be started from one of the 2 layers 但动作将从两层之一开始
view
layer (if it's from a user) view
层(如果来自用户) view model
layer (if it's a side-effect). view model
层(如果有副作用)。 But even it's from the view
, the view
will still call methods on view model
, and view model
will call some methods on model layer or you can simply update it in the view model layer depends on the cases(because you get the single source of truth). 但是即使是从
view
, view
仍将调用view model
上的方法, view model
将在模型层上调用某些方法,或者您可以根据情况在视图模型层中简单地对其进行更新(因为您获得了真相)。
It's kind of like Redux pattern - a nearly unidirectional data flow, where every change will happen at model layer and reflect back to view model layer, then bubble up to view layer.
这有点像Redux模式-几乎是单向的数据流,其中每个更改都将在模型层发生并反射回视图模型层,然后冒泡到视图层。 It's easy to reason about your data flow.
关于数据流的推理很容易。
Because everything is now connected to a single source of truth(a shared model layer), but, in a decoupled manner. 因为现在所有事物都连接到单个真理源(共享模型层),但是以分离的方式进行。 Every layer does its own job.
每个层都有自己的工作。
In order to get Transformations.map
to work, you need to observe
the result in the view, otherwise, that subscription from Transformations.map
will not work at all. 为了使
Transformations.map
正常工作,您需要在视图中observe
结果,否则,从Transformations.map
订阅将根本无法工作。
You can put your shared data in a Service , then in your fragment/activity's onResume
methods you can get updated data from there. 您可以将共享数据放在Service中 ,然后在片段/活动的
onResume
方法中从那里获取更新的数据。
To update your current fragment/activity you can fire an event when you update data in the Service, registering your fragment/activity to catch it and consequently update your showed data. 要更新您当前的片段/活动,您可以在更新服务中的数据时触发一个事件,注册您的片段/活动以捕获该片段/活动,从而更新您显示的数据。 You could use OttoBus to achieve this goal
您可以使用OttoBus实现此目标
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.