React 变更 - .NET SDK
所有 Realm 对象都是活动对象,这意味着它们在修改时会自动更新。每当任何属性发生变化时,Realm 都会发出通知事件。
Realm 的通知系统允许您监视数据更改并做出 React,而与导致更改的写入无关。要观察更改,您可以为要观察的 Realm、托管集合或 Realm 对象创建通知处理程序。 然后,您可以添加与更改相关的特定应用逻辑。
注意
有关将数据更改绑定到项目中的用户界面的信息,请参阅数据绑定。
Realm 会发出三种通知:
每当特定 Realm 提交写事务时,Realm 都会收到 Realm 通知。
每当托管集合发生任何更改时(例如插入、更新和删除集合中的对象),都会收到集合通知。
每当特定 Realm 对象发生更改时,都会收到对象通知。
注意
通知仅在 Realm 定期刷新时才起作用。 在应用程序的主线程或用户界面线程中,Realm 刷新会自动发生。 在后台线程上,您需要自己处理此问题,方法是调用 Realm.Refresh() 或安装 SynchronizationContext 在打开 Realm 之前在线程上执行此操作。第三方库 Nito.AsyncEx.Context 提供了SynchronizationContext
实现以及用于安装它的便捷 API。
注册 Realm 变更监听器
您可以在整个 Realm 上注册通知处理程序。 每当提交该 域 上的任何写事务(write transaction)时,Realm 都会调用通知处理程序。
处理程序不会收到有关变更的特定信息。 当您想知道是否有更改但不需要具体知道发生了什么更改时,此功能非常有用。
假设您正在构建一个实时协作应用程序,并且希望有一个计数器在每次进行更改时都会增加。 在这种情况下,您可以订阅域通知处理程序并添加控制该指标的代码。
// Observe realm notifications. realm.RealmChanged += (sender, eventArgs) => { // The "sender" object is the realm that has changed. // "eventArgs" is reserved for future use. // ... update UI ... };
注意collection更改
您可以监视 Realm 对象集合以及对象上 Realm集合属性的更改。 有两种方法可以获得有关集合变更的通知:在集合上注册通知处理程序或处理 CollectionChanged 事件。
注册集合变更监听器
您可以在特定的collection中的域上注册通知处理程序。该collection可以是 Realm 对象(例如realm.All<Person>()
),也可以是 Realm 对象上的属性(例如house.Owners
,其中 "Owners" 的类型为IList
)。
处理程序接收自上次通知以来对collection所做更改的描述。与 Realm 范围的通知不同,集合通知包含有关更改的详细信息,并提供管理用户界面中表示集合的列表或其他视图所需的信息。
添加订阅时,Realm 会发出初始通知。 在初始通知之后,每当写事务(write transaction)添加、修改或删除collection中的对象时,Realm 都会异步传递通知。
具体来说,该通知包含一个具有6属性的ChangeSet :
DeletedIndices
是一个int[]
,其中包含已删除对象的索引。InsertedIndices
是一个int[]
,其中包含已插入对象的索引。ModifiedIndices
是一个int[]
,其中包含已修改对象的旧索引。 这些索引指示在发生任何删除或插入操作之前,已修改对象在原始集合中的位置。NewModifiedIndices
是一个int[]
ModifiedIndices
,表示与属性相同的条目,但索引表示考虑所有更改后collection中的新位置。IsCleared
是一个布尔值,当通过调用Clear()
方法清除collection时,该值设置为true
。Moved
是一个ChangeSet.Move结构体数组,其中包含在集合中移动的对象的上一个索引和新索引。
若要订阅集合通知,请调用SubscribeForNotifications方法。 SubscribeForNotifications
返回一个订阅令牌,可随时处理该令牌以停止接收有关集合的通知。
以下代码演示了如何观察collection的更改。
// Watch for collection notifications. var subscriptionToken = realm.All<Dog>() .SubscribeForNotifications((sender, changes) => { if (changes == null) { // This is the case when the notification is called // for the first time. // Populate tableview/listview with all the items // from `collection` return; } // Handle individual changes foreach (var i in changes.DeletedIndices) { // ... handle deletions ... } foreach (var i in changes.InsertedIndices) { // ... handle insertions ... } foreach (var i in changes.NewModifiedIndices) { // ... handle modifications ... } if (changes.IsCleared) { // A special case if the collection has been cleared: // i.e., all items have been deleted by calling // the Clear() method. } });
重要
顺序很重要
在collection通知处理程序中,始终按以下顺序应用更改:
删除
插入
修改
在删除操作之前处理插入操作可能会导致意外行为。
取消注册变更监听器
要取消注册变更侦听器,请对令牌调用Dispose
。 以下代码演示了如何执行此操作:
// Watch for collection notifications. // Call Dispose() when you are done observing the // collection. var token = realm.All<Dog>() .SubscribeForNotifications((sender, changes) => { // etc. }); // When you no longer want to receive notifications: token.Dispose();
处理 CollectionChanged 事件
每个 Realm 集合都实现了INotifyCollectionChanged
,这允许您直接在数据绑定场景中使用集合。 由于集合实现了INotifyCollectionChanged
,因此监控集合更改的另一种方法是处理 CollectionChanged 事件,并检查 NotifyCollectionChangedAction 的类型。
重要
不太详细的信息
CollectionChanged
事件处理程序提供的更改详细信息级别与SubscribeForNotifications
不同。
以下代码向您展示如何实施CollectionChanged
事件处理程序:
{ // Subscribe to a query realm.All<Dog>().AsRealmCollection().CollectionChanged += HandleCollectionChanged; // Subscribe to a property collection gracie.Owners.AsRealmCollection().CollectionChanged += HandleCollectionChanged; ... } private void HandleCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { // Use e.Action to get the // NotifyCollectionChangedAction type. if (e.Action == NotifyCollectionChangedAction.Add) { // etc. } }
注册对象变更侦听器
您可以在 域 中的特定对象上注册通知处理程序,以便 SDK 在对象的任何属性发生更改时通知您。处理程序接收有关哪个字段已更改的信息。 通过字段名称,您可以获取新值。
以下代码演示了如何观察对象的更改。
var artist = realm.All<Person>() .FirstOrDefault(p => p.Name == "Elvis Presley"); artist.PropertyChanged += (sender, eventArgs) => { var changedProperty = eventArgs.PropertyName!; Debug.WriteLine( $@"New value set for 'artist': '{changedProperty}' is now {artist.GetType() .GetProperty(changedProperty).GetValue(artist)}"); }; realm.Write(() => { artist.Name = "Elvis Costello"; }); realm.Refresh(); }
取消注册变更监听器
当您不想再接收有关变更侦听器的通知时,可以取消注册处理程序。 对于 Realm 对象集合和集合属性,该代码是相同的。 以下代码展示了如何在两者上取消注册变更侦听器:
// Unsubscribe from notifications on a // realm listener realm.RealmChanged -= OnRealmChanged; // Unsubscribe from notifications on a // collection of realm objects realm.All<Item>().AsRealmCollection() .CollectionChanged -= OnItemsChangedHandler; // Unsubscribe from notifications on a // collection property items.AsRealmCollection().CollectionChanged -= OnItemsChangedHandler;
变更通知限制
嵌套文档中深度超过四级的变更不会触发变更通知。
如果您的数据结构需要侦听第五层深度或更深层的更改,解决方法包括:
重构模式以减少嵌套。
添加“推送以刷新”一类的内容,使用户能够手动刷新数据。