Friday, October 12, 2018

Are there any possible performance issues if I run an Async method that runs every minute and is called from App.Xaml.cs OnStart()?

Leave a Comment

I have this code and my intention is that when the application is open then it will run a method called PointChecker.CheckPoints(); every minute.

This method runs an update against my database synchronously with db2.Execute("UPDATE ..... etc");

From what I understand by reading this:

https://xamarinhelp.com/xamarin-forms-async-task-startup/

There are a few different ways that I could implement this.

What I would like to know is if there are any performance issues with running the code like this that could be reduced if I was to look into running it in a different way. In particular have there been any recent changes to the way Xamarin.Forms works (my app runs on iOS and Android through Forms), that I should consider and that might lead to a better way of doing this task.

    public App() {         InitializeComponent();         DB.PopulateTables();         MainPage = new Japanese.MainPage();     }      protected override async void OnStart() {         await Task.Run(() => {             StartTimer();         });     }      public void StartTimer() {        if (!stopWatch.IsRunning)           stopWatch.Start();           Device.StartTimer(new TimeSpan(0, 0, 1), () => {              if (stopWatch.IsRunning && stopWatch.Elapsed.Minutes >= 1) {                 PointChecker.CheckPoints();                 stopWatch.Restart();              }              return true;           });     }     protected override void OnSleep() {         stopWatch.Reset(); base.OnSleep();     }     protected override void OnResume() {         base.OnResume(); stopWatch.Start();     } 

3 Answers

Answers 1

Recent changes to Xamarin should not affect this. This method is the most efficient way. The only thing I would consider is why your method needs to be async. You can call:

 protected override void OnStart() 

In another thread a solution which was non-UI blocking was discussed:

using Xamarin.Forms; using System; using System.Linq; using System.Diagnostics;  namespace YourNamespace {     public partial class App : Application     {         private static Stopwatch stopWatch = new Stopwatch();         private const int defaultTimespan = 1;          protected override void OnStart()         {             // On start runs when your application launches from a closed state,               if (!StopWatch.IsRunning)             {                 StopWatch.Start();             }              Device.StartTimer(new TimeSpan(0, 0, 1), () =>             {                 // Logic for logging out if the device is inactive for a period of time.                  if (StopWatch.IsRunning && StopWatch.Elapsed.Minutes >= defaultTimespan)                 {                     //prepare to perform your data pull here as we have hit the 1 minute mark                             // Perform your long running operations here.                          InvokeOnMainThread(()=>{                             // If you need to do anything with your UI, you need to wrap it in this.                         });                      stopwatch.Restart();                 }                  // Always return true as to keep our device timer running.                 return true;             });         }          protected override void OnSleep()         {             // Ensure our stopwatch is reset so the elapsed time is 0.             StopWatch.Reset();         }          protected override void OnResume()         {             // App enters the foreground so start our stopwatch again.             StopWatch.Start();         }     } } 

Best of all, this method is

Platform agnostic

Answers 2

Reference Async/Await - Best Practices in Asynchronous Programming

By using async void you remove the ability for your code to catch and handle any exceptions that may be thrown by the invocation of the timer. So avoid using async void on anything except event handlers.

OnStart however is not an event handler. Just a regular method that according to documentation...

Application developers override this method to perform actions when the application starts.

As a work around you can create your own custom event and handler that will allow for an async void to be performed on your event handler. You will subscribe to the event when OnStart is invoked by the application and then raise the custom event to be handled asynchronously.

StartTimer is not a heavy method so does not really warrant being invoked asynchronously. The PointChecker.CheckPoints() however is stated as being called against your database synchronously.

This method runs an update against my database synchronously with db2.Execute("UPDATE ..... etc");

This could however cause blocking which could affect performance every time it is invoked. That should be the one wrapped in an async call or refactored to be native async method.

//...  protected override void OnStart() {     PointsChecking += OnPointsChecking; //subscribe to event     StartTimer(); //start the timer as normal. }  private event EventArgs PointsChecking = delegate { };  private async void OnPointsChecking(object sender, EventArgs args) {     //asynchronously check points without blocking main thread     await Task.Run(() => {         PointChecker.CheckPoints();         stopWatch.Restart();     }); }  public void StartTimer() {     if (!stopWatch.IsRunning)         stopWatch.Start();     Device.StartTimer(new TimeSpan(0, 0, 1), () => {         if (stopWatch.IsRunning && stopWatch.Elapsed.Minutes >= 1) {             PointsChecking(null, EventArgs.Empty); //invoked event         }         return true;     }); }  //... 

The timer would be responsible for raising the event to handle the repeated operation. By making the event handler async you avoid blocking main thread and have the added advantage of being able to catch and handler any exceptions thrown by the invoked database operation, if so desired.

Answers 3

I have the same scenario to sync data on given time interval, so I have used android native service Sync Adapter. What it does basically instead of managing the call on the given interval it will hand over to your Android OS. I don't have any idea on iOS how you can achieve this.

If you want to implement sync adapter use this Sample Code

I think this is the best solution for Android.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment