简体   繁体   中英

Observable | Subscribe to get only the changed objects

I have a list of Objects that I get from Realtime-Database (Firebase) with a wrapper in C# Firebase.Xamarin

private List<Job> jobList = null;

which populates at first the application is loaded using the following code:

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();
}

I want to subscribe the DB to fire an event and change/add new Objects to the list and fire an event afterwords to show or notify the user for one time, a change has been occurred. For this purpose I am using the Observable ie Reactive Rx.Net with All in the following way:

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

Is there any thing wrong with the code? Moreover, where should I create the event that a change has arrived?

First I would recommend getting rid of the foreach/Add , it is the work for 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();
}

Then I would use Where . How you use All is weird, it is an extension method and you call it like a usual static method. It is possible but it is now how it should be used. Here is the code with Where :

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

Thanks to @Alexey Zimarev for giving me a quick click, and the flowing code came into appearance: First Of all took a ConcurrentDictionary that as a data member and initialized the Firebaseclient and than populated the list ;

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();
}

Inside this function I initialized the dictionary and done the UI work, at last set the listeners respectively to monitor the change in 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();


}

Here i set the Insertion observer for the keys that are not available in the dictionary and than set the deletion observer for the keys that are available in the dictionary.

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: Assumption is here, I assume that the objects that we were adding in the above question and answer were not getting compared because of there memory existence. Like a new object was getting instantiated the might be different from its clone already existing in the list. Please correct me if I am wrong with respect to Linq behavior. However the above given code works in my scenario with dictionary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM