0
votes

I'm implementing an audio recorder in Xamarin.Forms. There should be a timer displaying the time the recorder is running. On tapping on a image, the recording starts, and if the user taps again, the recording stops. The tapped command code looks like:

    /// <summary>
    ///     The on tabbed command.
    /// </summary>
    private async void OnTappedCommand()
    {
        if (this.isRecording)
        {
            this.isRecording = false;
            await this.StopRecording().ConfigureAwait(false); // Stops the MediaRecorder
        }
        else
        {
            this.isRecording = true;
            await this.StartTimer().ConfigureAwait(false); // Starts the Timer
            await this.StartRecording().ConfigureAwait(false); // Starts the MediaRecorder
        }
    }

The StartTimer() method looks like:

private async Task StartTimer()
    {
        Device.StartTimer(
            new TimeSpan(0, 0, 0, 0, 1),
            () =>
                {
                    if (this.isRecording)
                    {
                        Device.BeginInvokeOnMainThread(
                            () =>
                                {
                                    this.TimerValue = this.TimerValue + 1;
                                });

                        return true;
                    }

                    Device.BeginInvokeOnMainThread(
                        () =>
                            {
                                this.TimerValue = 0;
                            });

                    return false;
                });
}

The TimerValue is a simple integer property bound to a label that's using a ValueConverter to handle the formatting.

My Questions are:

1. Why does my code work even if I remove the Device.BeginInvokeOnMainThread method? Shouldn't it throw an error because it's not running on the UI-Thread and trying to update the UI-Bound TimerValue Property, since ConfigureAwait(false) is used?

2. Where do you suggest to use Task.Run() in this code, or should'nt it be used at all?

1
1) The compiler is giving you a warning that StartTimer runs synchronously; don't ignore it. 2) What does Device.StartTimer do?Stephen Cleary
I would recommend to count the recording time with a System.Diagnostics.Stopwatch because your method will result in a wrong TimerValue.Norman Schütt

1 Answers

0
votes

1 - It works because the timer will run the code in the UI Thread (Main Thread). The same used by Device.BeginInvokeOnMainThread(). You can use it when your code is running out of the UI Thread (see the next answer)

2 - Should'nt it be used at all in your example because this.TimerValue was created by (and is property of) the UI Thread Task.Run() execute the code in a "thread pool" and cannot touch the objects created by the "UI Thread". The "Thread Pool" is to be used for long jobs and that should not interact with the UI.