可观察的|订阅仅获取已更改的对象

时间:2017-01-22 16:11:33

标签: c# linq xamarin.android firebase-realtime-database observer-pattern

我有一个从Realtime-Database (Firebase)获得wrapper in C# Firebase.Xamarin

的对象列表
private List<Job> jobList = null;

首先填充应用程序,使用以下代码加载:

private async void PopulateList()
{
     IReadOnlyCollection<Firebase.Xamarin.Database.FirebaseObject<Job>>  items = await firebase
        .Child("jobs")
        .OnceAsync<Job>();
    jobList = new List<Job>();
    foreach (var item in items)
    {
         jobList.Add(
             new Job 
             { 
                  ID = item.Object.ID, 
                  StartDate = item.Object.StartDate, 
                  EndDate = item.Object.EndDate, 
                  Description = item.Object.Description 
              });
        }
    SubscribeDbChanges();
}

我想订阅数据库以触发事件并将新对象更改/添加到列表中并触发事件后显示或通知用户一次,发生了更改。为此我使用了Observable,Reactive Rx.Net with All 通过以下方式:

private void SubscribeDbChanges()
{
     Observable.All<FirebaseEvent<Job>>(
          firebase
              .Child("jobs")
              .AsObservable<Job>(), 
          job => !jobList
              .Contains(job.Object))
          .Subscribe(jobItem =>
              {
              });
}

代码有什么问题吗?此外,我应该在哪里创建变更已到达的事件?

2 个答案:

答案 0 :(得分:3)

首先我建议删除foreach/Add,这是Select

的工作
private async void PopulateList()
{
    jobList = (await firebase
        .Child("jobs")
        .OnceAsync<Job>())
        .Select(item =>
             new Job 
             { 
                  ID = item.Object.ID, 
                  StartDate = item.Object.StartDate, 
                  EndDate = item.Object.EndDate, 
                  Description = item.Object.Description 
              });
    SubscribeDbChanges();
}

然后我会使用Where。你如何使用All很奇怪,它是一个扩展方法,你称之为通常的静态方法。这是可能的,但现在应该如何使用它。以下是包含Where的代码:

private void SubscribeDbChanges()
{
    firebase
        .Child("jobs")
        .AsObservable<Job>()
        .Where(job => !jobList.Contains(job.Object))
        .Subscribe(jobItem =>
            {
            });
}

答案 1 :(得分:1)

感谢@Alexey Zimarev给我一个快速点击,流畅的代码出现了: 首先采用ConcurrentDictionary作为数据成员并初始化 Firebaseclient ,然后填充列表;

FirebaseClient firebase;
private ConcurrentDictionary<string, Job> jobList ;
protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);
    firebase = new FirebaseClient("https://samplehosting-XXXX.firebaseio.com/");
    PopulateList();
}

在这个函数中我初始化了字典并完成了 UI 工作,最后分别设置了监听器来监控 SubscribeToDbChanges

中的变化
private async void PopulateList()
{
    IReadOnlyCollection<Firebase.Xamarin.Database.FirebaseObject<Job>> items = await firebase
        .Child("jobs")
        .OnceAsync<Job>();
    jobList = new ConcurrentDictionary<string, Job>();

    foreach (var job in items)
    {
        while (!jobList.TryAdd(job.Object.ID, job.Object)) ;
    }
    list = FindViewById<ListView>(Resource.Id.listJobs);
    list.ChoiceMode = ChoiceMode.Single;
    HomeScreenAdapter ListAdapter = new HomeScreenAdapter(this, jobList);
    list.Adapter = ListAdapter;
    SubscribeToDbChanges();


}

在这里,我为字典中的键设置插入观察者,而不是为设置删除观察者字典中可用的键

private void SubscribeToDbChanges()
{
    firebase
    .Child("jobs").AsObservable<Job>()
    .Where(job => !jobList.ContainsKey(job.Object.ID) && job.EventType == Firebase.Xamarin.Database.Streaming.FirebaseEventType.InsertOrUpdate)
    .Subscribe(job =>
    {
        if (job.EventType == Firebase.Xamarin.Database.Streaming.FirebaseEventType.InsertOrUpdate)
        {
            while (!jobList.TryAdd(job.Object.ID, job.Object)) ;
        }
    });
    firebase
    .Child("jobs").AsObservable<Job>()
    .Where(job => jobList.ContainsKey(job.Object.ID) && job.EventType == Firebase.Xamarin.Database.Streaming.FirebaseEventType.Delete)
    .Subscribe(job =>
    {
        Thread remove = new Thread(() =>
        {
            Job removed = null;
            jobList.TryRemove(job.Object.ID, out removed);
        });
        remove.Start();
    });

}
PS:假设在这里,我假设我们在上面的问题和答案中添加的对象没有得到比较,因为存在存在。就像新对象被实例化一样,它可能与列表中已存在的克隆不同。如果我对Linq行为有误,请纠正我。但是上面给出的代码在我的场景中使用字典。