Here's the code that I have come up with. It seems to work but I am concerned that it may not be good way to do what I want to do. What I need is to run a method every minute as soon as the OnAppearing happens and have it stop with the OnDisappearing();
protected async override void OnAppearing()
{
base.OnAppearing();
BindingContext = vm;
cts = new CancellationTokenSource();
if (Settings.mode == MO.Practice)
{
if (!App.stopWatch.IsRunning) { App.stopWatch.Start(); }
Device.StartTimer(new TimeSpan(0, 0, 5), () =>
{
if (App.stopWatch.IsRunning && App.stopWatch.Elapsed.Seconds >= 60)
{
// Here's the method I want to run. After it's finished
// I call BeginInvoke .. to update info on the screen
if (App.DB.ReducePoints() == true)
Device.BeginInvokeOnMainThread(() =>
{
vm.PifInfo = GetPifInfo();
});
App.stopWatch.Restart();
}
return true;
});
}
await GetCards(cts.Token);
}
}
protected override void OnDisappearing()
{
Unsubscribe();
cts.Cancel();
if (App.stopWatch.IsRunning) { App.stopWatch.Stop(); }
base.OnDisappearing();
}
Not part of the question but I would welcome any comments on the code also.
You can do this simpler by returning the correct value from Device.StartTimer
, to repeat true
, to not repeat false
and not use a StopWatch
. (source states that While the callback returns true, the timer will keep recurring.
And as you see from the source, the method doesn't need a Func<Task<bool>>
it only needs a Func<bool>
callback so there is no need to use a Task
.)
in the class
volatile bool run;
in OnAppearing
run = true;
Device.StartTimer(new TimeSpan(0, 1, 0), () => {
if (run) { /*do what you want;*/ return true; }
else { return false; }
});
in OnDisappearing
run = false;
Here is the code. I am leaving my original answer to help anyone else who needs this.
volatile bool run;
protected async override void OnAppearing()
{
base.OnAppearing();
BindingContext = vm;
cts = new CancellationTokenSource();
if (Settings.mode == MO.Practice)
{
run = true;
Device.StartTimer(new TimeSpan(0, 1, 0), () =>
{
if (run)
{
if (App.DB.ReducePoints() == true)
Device.BeginInvokeOnMainThread(() =>
{
vm.PifInfo = GetPifInfo();
});
return true;
}
else { return false; }
});
await GetCards(cts.Token);
}
}
protected override void OnDisappearing()
{
run = false;
Unsubscribe();
cts.Cancel();
base.OnDisappearing();
}
You can refactor the code to make proper use of the Timer in combination with a CancellationToken
.
Also note the use of the async event handler to avoid the fire and forget call to async void OnAppearing
that won't allow thrown exceptions to be caught and can cause crashes.
CancellationTokenSource source;
protected override void OnAppearing() {
base.OnAppearing();
BindingContext = vm;
timerStarted += onTimerStarted;
timerStarted(this, EventArgs.Empty);
}
private event EventHandler timerStarted = delegate { };
private async void onTimerStarted(object sender, EventArgs args) {
timerStarted -= onTimerStarted;
cts = new CancellationTokenSource();
if (Settings.mode == MO.Practice) {
source = new CancellationTokenSource();
StartTimer(source.Token);
await GetCards(cts.Token);
}
}
private void StartTimer(CancellationToken token) {
var interval = TimeSpan.FromMinutes(1);
Func<bool> callback = () => {
//check if to stop timer
if(token.IsCancellationRequested) return false;
//Code to be repeated
checkPoints();
//While the callback returns true, the timer will keep recurring.
return true;
};
//repeat this function every minute
Device.StartTimer(interval, callback);
}
private void checkPoints() {
// Here's the method I want to run. After it's finished
// I call BeginInvoke .. to update info on the screen
if (App.DB.ReducePoints() == true) {
Device.BeginInvokeOnMainThread(() => {
vm.PifInfo = GetPifInfo();
});
}
}
protected override void OnDisappearing() {
source.Cancel();//Timer will short-circuit on next interval
Unsubscribe();
cts.Cancel();
base.OnDisappearing();
}
The cancellation token will be used to force the timer to return false
and stop recurring when the token is cancelled in OnDisappearing()
.
If the function to be repeated needs to be asynchronous add another async event handler to manage that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With