How to get the current timer status and continue running after the app is closed and reopened?

der_sharky 21 Reputation points
2021-05-24T12:19:35.967+00:00

I have programmed an app in Xamarin form (Android) that has a timer and I have programmed everything in MainPage.cs class. Everything works correctly until now only when I close the app(sending to background) and open it again. The problem is that when I open the app again then the timer no longer runs but it simply displays the remaining time at the moment of opening the app.The timer is not running. I have read that Xamarin Forms calls the OnSleep, OnResume method in this case and you should program there that the timer is retrieved correctly again and continues to run. I have little experience with it and could not find anything good after long research. Who knows how the timer can be retrieved and run again after opening. Thank you very much.
Here is my Timer Methode in Main Page

public void StartCountdown()
{    
    CancellationTokenSource tokenSource = new CancellationTokenSource();
    CancellationToken token = tokenSource.Token;

    if (cancel == true)
    {
        tokenSource.Cancel();
    }

    task = Task.Run(async () =>
   {
           Device.StartTimer(TimeSpan.FromSeconds(1), () =>
           {
               restTime -= TimeSpan.FromSeconds(1);
               if (cancel == true)
               {
                   return false;
               }
               if (restTime == zero)
               {
                   StartDownload();
                   return false; 
                }
               else
               {
                   Device.BeginInvokeOnMainThread(() =>
                   {
                       ActivateElements(false);
                   });

                   return true;                       }
           });

   }, token);
}
Developer technologies .NET Xamarin
{count} votes

Accepted answer
  1. Kyle Wang 5,531 Reputation points Microsoft External Staff
    2021-06-10T09:07:02.497+00:00

    Hi dersharky-6168,

    Welcome to our Microsoft Q&A platform!

    Here is a workaround you can try.

    Since it can work normally after clicking the Home button, we can override "OnBackButtonPressed" and use code to simulate pressing the Home button.

    Create a interface named "ISendToBackService".

    public interface ISendToBackService  
    {  
        void SendToBack();  
    }  
    

    Implement the method "SendToBack".

    [assembly: Dependency(typeof(SendToBackService))]  
    namespace wifitimertest.Droid  
    {  
        class SendToBackService : ISendToBackService  
        {  
            public void SendToBack()  
            {  
                var activity = (Activity)Forms.Context;  
                activity.MoveTaskToBack(true);  
            }  
        }  
    }  
    

    Last, override the method "OnBackButtonPressed".

    protected override bool OnBackButtonPressed()  
    {  
        DependencyService.Get<ISendToBackService>().SendToBack();  
        return true;  
    }  
    

    Rgerads,
    Kyle


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. der_sharky 21 Reputation points
    2021-06-01T11:54:06.89+00:00

    Helo KyleWang ,
    I am sorry for my later reply. I had vacation
    All I need is when the timer was started then in each app status (OnStart, OnResume, OnSleep) should run and the remaining time is displayed until really the time was elapsed. Practical example: The user opens the app sets the timer for 10 min then closes the app with home button or return button. After three minutes he opens the app and the time is set to 7 minutes and is continuously elapsed by the second. He can see every time he opens the app how the remaining time is running backwards by seconds. I use Android 10 now. The Problem is the UI for the remaining time is not updatet after the app is closed und again opened.

    Here is my Code:

    using System;  
    using System.ComponentModel;  
    using System.Threading;  
    using System.Threading.Tasks;  
    using Xamarin.Forms;  
      
    namespace WifiTimer  
    {  
        public partial class MainPage : ContentPage, INotifyPropertyChanged  
        {  
            public int minutes = 0;  
            public int hours = 0;  
      
      
            private static TimeSpan restTime = TimeSpan.Zero;  
      
            private string displayRemainTime = restTime.ToString(@"hh\:mm\:ss");  
      
      
      
            private Task task;  
      
            private bool cancel;  
      
            public string RemainingTime  
            {  
                get => displayRemainTime;  
                set  
                {  
                    displayRemainTime = value;  
                    OnPropertyChanged(value);  
      
                }  
            }  
      
            public event PropertyChangedEventHandler PropertyChanged;  
      
      
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
            }  
      
      
            PickersLists pickers = new PickersLists();  
      
             
            public MainPage()  
            {  
                //Am besten hier nur Methoden rein  
                InitializeComponent();  
                LoadPickerHours();  
                LoadPickerMinutes();  
                BindingContext = this;  
                LabelCountdown.Text = displayRemainTime;  
      
                Application.Current.Properties["task"] = task;  
      
                if (task != null)  
                {  
                    ActivateElements(false);  
                }  
            }  
      
      
      
            public void DisableWifi()  
            {  
      
                DependencyService.Get<IWifiManager>().CheckWifi();  
      
            }  
      
      
      
            public void StartButton_Clicked(object sender, EventArgs e)  
            {  
      
                if (task == null)  
                {  
                      
                    StartCountdown(hours, minutes);  
               
      
                }           
            }  
      
      
            public void StartCountdown(int hours, int min)  
            {  
                
                var M = TimeSpan.FromMinutes(min);  
                var H = TimeSpan.FromHours(hours);  
                var zero = TimeSpan.FromHours(0) + TimeSpan.FromMinutes(0) + TimeSpan.FromSeconds(0);  
                restTime = H.Add(M);  
      
                CancellationTokenSource tokenSource = new CancellationTokenSource();  
                CancellationToken token = tokenSource.Token;  
      
                if (cancel == true)  
                {  
                    tokenSource.Cancel();  
                }  
           
                task = Task.Run(async () =>  
                {  
                     
                    Device.StartTimer(TimeSpan.FromSeconds(1), () =>  
                       {  
                           DependencyService.Get<IAndroidService>().StartService();  
                           restTime -= TimeSpan.FromSeconds(1);  
      
                           displayRemainTime = restTime.ToString(@"hh\:mm\:ss");  
      
                           LabelCountdown.Text = RemainingTime;  
      
                           if (cancel == true)  
                           {  
                               PickerHours.SelectedIndex = 0;  
                               PickerMinutes.SelectedIndex = 0;  
                               ActivateElements(true);  
                               LabelCountdown.Text = zero.ToString(@"hh\:mm\:ss");  
                               cancel = false;  
                               task = null;                  
                               return false;  
                           }  
      
                           if (restTime == zero)  
                           {  
                               DisableWifi();  
                               DependencyService.Get<IAndroidService>().StopService();  
                               PickerHours.SelectedIndex = 0;  
                               PickerMinutes.SelectedIndex = 0;  
                               ActivateElements(true);  
                               task = null;  
                               return false; //false timer wird ausgeschaltet  
                           }  
                           else  
                           {  
                               Device.BeginInvokeOnMainThread(() =>  
                               {  
                                   ActivateElements(false);  
                               });  
      
      
                               return true; //true timer wird wiederholt  
                           }  
                       });  
      
               }, token);  
            }  
      
            public void ActivateElements(bool visible)  
            {  
                StartButton.IsEnabled = visible;  
                LabelHours.IsEnabled = visible;  
                DelimiterTime.IsEnabled = visible;  
                LabelMinutes.IsEnabled = visible;  
                PickerHours.IsEnabled = visible;  
                PickerMinutes.IsEnabled = visible;  
            }  
      
      
            public void StopButton_Clicked(object sender, EventArgs e)  
            {  
                if (task != null)  
                {  
                    cancel = true;  
                }  
            }  
      
      
      
      
            public void PickerHours_SelectedIndexChanged(object sender, EventArgs e)  
            {  
                var selectedHours = PickerHours.Items[PickerHours.SelectedIndex];  
      
                var selectedHoursToInt = int.Parse(selectedHours);  
      
                hours = selectedHoursToInt;  
            }  
      
      
            public void PickerMinutes_SelectedIndexChanged(object sender, EventArgs e)  
            {  
                var selectedMinutes = PickerMinutes.Items[PickerMinutes.SelectedIndex];  
      
                var selectedMinutesToInt = int.Parse(selectedMinutes);  
      
                minutes = selectedMinutesToInt;  
            }  
      
      
            public void LoadPickerHours()  
            {  
                PickerHours.ItemsSource = pickers.hoursList;  
                PickerHours.SelectedIndex = 0;  
            }  
      
      
            public void LoadPickerMinutes()  
            {  
                PickerMinutes.ItemsSource = pickers.minutesList;  
                PickerMinutes.SelectedIndex = 0;  
      
            }  
        }  
    }  
    
    
    
    
      
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.