Xamarin Media Plugin error: Only one operation can be active at at time
I’ve been getting System.InvalidOperationException: Only one operation can be active at a time
in a Xamarin app I’ve created which uses the Media Plugin, and finally figured out why I was getting it. I was being spectacularly stupid.
I was triggering the taking of a photo in a form’s Appearing
event handler
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:behaviors="clr-namespace:QuickNote.Behaviors;assembly=QuickNote"
xmlns:viewModels="clr-namespace:QuickNote.Shared.ViewModels;assembly=QuickNote"
BindingContext="{x:Static viewModels:Locator.ExecuteQuickNote}"
x:Class="QuickNote.ExecuteQuickNotePage" >
<ContentPage.Behaviors>
<behaviors:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadCommand}" />
</ContentPage.Behaviors>
<StackLayout Orientation="Vertical">
...
The relevant line is the binding to the LoadCommand
in the view model, which looked like this:
LoadCommand = new Command(async () => {
var options = new StoreCameraMediaOptions();
using(var file = await CrossMedia.Current.TakePhotoAsync(options))
{
if (file == null) {
Debug.WriteLine("No photo");
return;
}
Debug.WriteLine("Got a photo");
}
});
The behavior I was seeing was that when the form loaded, the camera started, I took a photo, tapped the Use Photo
button and then the app crashed with System.InvalidOperationException: Only one operation can be active at a time
.
Can you guess why? I finally realized that after taking the photo it was re-displaying the form, causing the appearing
event to be fired again, and thus causing a new photo to be taken while the old one was being taken. Hence the crash. D’oh.
My clue was that I discovered that by inserting a await Task.Yield();
at the start of the LoadCommand
delegate, it stopped the crash, but started the camera again after I’d finished taking a photo.
The solution was to add a flag which I checked to ensure I didn’t run the command more than once:
LoadCommand = new Command(async () => {
if(_loaded) return;
_loaded = true;
...
The error was perfectly correct, I was causing more than one “take photo” operation to be active at the same time, I just didn’t realize why.