locked
Is it possible the timer works when phone locked? RRS feed

  • Question

  • User394398 posted

    Hello everyone) In my app there is System.Timers.Timer in core layer, cuz I’m going to make an android version in the future so nvm) I got simply timer, and is it possible to keep it working when device locked or application in background?? `private void SetTimer() {

        Timer = new Timer
        {
            Interval = 1000,
            Enabled = true
        };
    
        Timer.Elapsed += TimerElapsed;
        Timer.Start();
    }
    
    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        if (_seconds == 59)
        {
            _minutes++;
            _seconds = 0;
        }
    
        Time = _minutes.ToString("00") + ":" + _seconds.ToString("00");
        _seconds++;
    }`
    
    Monday, July 6, 2020 10:32 AM

All replies

  • User369979 posted

    We could use UIApplication.SharedApplication.BeginBackgroundTask to allow the application to run some background tasks. But this won't last too long. The system will kill your app if the remaining time has reached 0 but the task hasn't been ended. Try to make the timer available in the background using it like:

    nint bgTask;
    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        bgTask = UIApplication.SharedApplication.BeginBackgroundTask(() =>
        {
            if (bgTask != UIApplication.BackgroundTaskInvalid)
            {
                UIApplication.SharedApplication.EndBackgroundTask(bgTask);
                bgTask = UIApplication.BackgroundTaskInvalid;
            }
       });
    
    
        if (_seconds == 59)
        {
            _minutes++;
            _seconds = 0;
        }
        Time = _minutes.ToString("00") + ":" + _seconds.ToString("00");            
        _seconds++;
    }
    

    But I think this is not very appropriate for your case here as the system will only give imitated time to run the code in the background. For true background task please refer to background mode: https://docs.microsoft.com/en-us/xamarin/ios/app-fundamentals/backgrounding/ios-backgrounding-techniques/registering-applications-to-run-in-background It will be better to calculate the interval when the app entered in the background. Record the leaving date in the DidEnterBackground of SceneDelegate after iOS 13:

    NSDate backgroundDate;
    
    // Get the interval when coming back
    [Export ("sceneWillEnterForeground:")]
    public void WillEnterForeground (UIScene scene)
    {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
        if (backgroundDate != null)
        {
            var interval = NSDate.Now.GetSecondsSince(backgroundDate);
            NSNotificationCenter.DefaultCenter.PostNotificationName("calculate", null, NSDictionary.FromObjectAndKey(NSNumber.FromDouble(interval), new NSString("interval")));
        }
    
    }
    
    [Export ("sceneDidEnterBackground:")]
    public void DidEnterBackground (UIScene scene)
    {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    
        backgroundDate = NSDate.Now;
    }
    

    Register this notification on the page like:

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
        // Perform any additional setup after loading the view, typically from a nib.
    
        NSNotificationCenter.DefaultCenter.AddObserver(new NSString("calculate"), (notification) =>
        {
            var interval = ((NSNumber)notification.UserInfo["interval"]).Int32Value;
            int total = interval + _seconds + 60 * _minutes;
            _seconds = total % 60;
            _minutes = total / 60;
        });
    }
    

    This will also get the expected result without a background process. Moreover, handle theDidEnterBackground and WillEnterForeground events of AppDelegate before iOS 13.

    Tuesday, July 7, 2020 8:15 AM
  • User394398 posted

    @LandLu said: We could use UIApplication.SharedApplication.BeginBackgroundTask to allow the application to run some background tasks. But this won't last too long. The system will kill your app if the remaining time has reached 0 but the task hasn't been ended. Try to make the timer available in the background using it like:

    nint bgTask;private void TimerElapsed(object sender, ElapsedEventArgs e){ bgTask = UIApplication.SharedApplication.BeginBackgroundTask(() => { if (bgTask != UIApplication.BackgroundTaskInvalid) { UIApplication.SharedApplication.EndBackgroundTask(bgTask); bgTask = UIApplication.BackgroundTaskInvalid; } }); if (_seconds == 59) { _minutes++; _seconds = 0; } Time = _minutes.ToString("00") + ":" + _seconds.ToString("00"); _seconds++;}

    Hey, TimerElapsed call every timer.interval time, in my case it every 1 sec, why we start new backgroundTask every 1 sec or how it working?

    Tuesday, July 7, 2020 11:16 AM
  • User369979 posted

    We only need to call BeginBackgroundTask for the first time the timer starts to be triggered.

    Wednesday, July 8, 2020 9:07 AM