Search code examples
angularnativescriptproperty-binding

Delay with property binding in NativeScript Angular app


I am building a NativeScript Angular app with the nativescript-pedometer plugin. I set up an Observable to report new steps. When new steps are reported, I log the number to the console, update a property on the Home component and call ApplicationRef.tick().

The number in the UI does change, but only after a delay of at least five seconds and sometimes as long as a minute, between the time I see it in the console and the time I see it in the UI.

Instead of ApplicationRef.tick() I also tried NgZone.run(callback) and ChangeDetectorRef.detectChanges(). There's a delay with any of them. If I don't include any of them, the UI never updates.

I should mention I've only tested this on iOS devices and don't know for sure whether the issue would happen on Android.

Here's home.component.ts:

import { Component, OnInit, ApplicationRef } from "@angular/core";
import { Pedometer } from "nativescript-pedometer";
import { Observable } from "rxjs";
import { take } from "rxjs/operators";

@Component({
  selector: "Home",
  moduleId: module.id,
  templateUrl: "./home.component.html"
})
export class HomeComponent implements OnInit {
  numSteps: number;
  pedometer: Pedometer;

  constructor(private applicationRef: ApplicationRef) {}

  ngOnInit(): void {
    this.numSteps = 0;
    this.pedometer = new Pedometer();

    this.startUpdates().subscribe(response => {
      console.log('New step count received from pedometer:');
      console.log(response.steps);
      this.numSteps = response.steps;
      this.applicationRef.tick();
    });
  }

  startUpdates(): Observable<any> {
    return Observable.create(observer => {
      this.pedometer.startUpdates({
        onUpdate: result => observer.next(result)
      });
    }).pipe(take(25));
  }
}

And here's home.component.html:

<StackLayout>
    <Label text="Number of steps is:"></Label>
    <Label [text]="numSteps"></Label>
</StackLayout>

Solution

  • onUpdate is called from background thread and Angular is on UI thread. Try this,

    startUpdates(): Observable<any> {
     return Observable.create(observer => {
      this.pedometer.startUpdates({
        onUpdate: result => Promise.resolve().then(() => observer.next(result))
      });
     }).pipe(take(25));
    }
    

    Promise.resolve() forces the block into UI thread.