Need an example of take a Picture with MonoDroid and MVVMCross
android, camera, mvvmcross, xamarin.android
Solution
I generally implement a service using the built-in `IMvxPictureChooserTask` (this is in a Plugin if using vNext):
using Cirrious.MvvmCross.ExtensionMethods;
using Cirrious.MvvmCross.Interfaces.Platform.Tasks;
using Cirrious.MvvmCross.Interfaces.ServiceProvider;
public class PhotoService
: IMvxServiceConsumer<IMvxPictureChooserTask>
, IPhotoService
{
private const int MaxPixelDimension = 1024;
private const int DefaultJpegQuality = 92;
public void GetNewPhoto()
{
Trace.Info("Get a new photo started.");
this.GetService<IMvxPictureChooserTask>().TakePicture(
MaxPixelDimension,
DefaultJpegQuality,
HandlePhotoAvailable,
() => { /* cancel is ignored */ });
}
public event EventHandler<PhotoStreamEventArgs> PhotoStreamAvailable;
private void HandlePhotoAvailable(Stream pictureStream)
{
Trace.Info("Picture available");
var handler = PhotoStreamAvailable;
if (handler != null)
{
handler(this, new PhotoStreamEventArgs() { PictureStream = pictureStream });
}
}
}
I generally register this service as a singleton during startup, and then call it from a ViewModel ICommand handler.
One app which uses this service is the Blooor sample - see BaseEditProductViewModel.cs - this isn't a sample I had anything to do with, but I believe it brings in both Picture taking and ZXing - both using external services.
One warning: On MonoDroid, you can see some strange/unexpected Activity/ViewModel lifecycle behaviour - basically you can see that the Activity you take the photo from is unloaded/wiped from memory during the photo taking. If this happens to your app then you'll probably need to start looking at questions like: Saving Android Activity state using Save Instance State - this isn't automatically handled in MvvmCross (yet).
I believe the Blooor sample might suffer from this issue - but whether a user would ever see it in normal app use is debatable.
As an alternative to the `IMvxPictureChooserTask` service, you can also look at using some of the cross-platform APIs from Xamarin.Mobile - see MvvmCross vnext : monodroid use a VideoView inside a plugin for a possible starting place - or for Android only you can easily implement your own.
Problem
Can anyone point me to an example of take a Photo and store it using `MVVMCross`? I have been searching but only have found this: Monodroid Take a picture with Camera (Doesn't Implement MVVMCross) Video Recording (It's Video and i can't make it work :S) The Oficialy Recipe Example (It Works but does not implement MVVMCross) Thanks!!! Resolved! Thanks! To Future References: (Using Master Branch) Credits to Stuart, I just changed the code to work with my reality ``` using Cirrious.MvvmCross.ExtensionMethods; using Cirrious.MvvmCross.Interfaces.Platform.Tasks; using Cirrious.MvvmCross.Interfaces.ServiceProvider; using SIGEP.DummyService; using SIGEP.Mobile.Core.Interfaces; namespace SIGEP.Mobile.Core.Models { public class PhotoService : IMvxServiceConsumer<IMvxPictureChooserTask> { private const int MaxPixelDimension = 1024; private const int DefaultJpegQuality = 92; public void GetNewPhoto() { this.GetService<IMvxPictureChooserTask>().TakePicture( MaxPixelDimension, DefaultJpegQuality, HandlePhotoAvailable, () => { /* cancel is ignored */ }); } public event EventHandler<PhotoStreamEventArgs> PhotoStreamAvailable; private void HandlePhotoAvailable(Stream pictureStream) { var handler = PhotoStreamAvailable; if (handler != null) { handler(this, new PhotoStreamEventArgs() { PictureStream = pictureStream, OnSucessGettingPhotoFileName = OnSucessGettingPhotoFileName }); } } public static void TakePhoto(Action<string> successFileName, Action<Exception> error) { var service = new PhotoService(); service.OnSucessGettingPhotoFileName = successFileName; service.OnError = error; service.GetNewPhoto(); service.PhotoStreamAvailable += new EventHandler<PhotoStreamEventArgs>(service_PhotoStreamAvailable); } static void service_PhotoStreamAvailable(object sender, PhotoStreamEventArgs e) { //grava pra ficheiro!!! var directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var filename = Path.Combine(directory, "photo.jpeg"); string saveTo = filename; FileStream writeStream = new FileStream(saveTo, FileMode.Create, FileAccess.Write); ReadWriteStream(e.PictureStream, writeStream); e.OnSucessGettingPhotoFileName(filename); } private static void ReadWriteStream(Stream readStream, Stream writeStream) { int Length = 256; Byte[] buffer = new Byte[Length]; int bytesRead = readStream.Read(buffer, 0, Length); // write the required bytes while (bytesRead > 0) { writeStream.Write(buffer, 0, bytesRead); bytesRead = readStream.Read(buffer, 0, Length); } readStream.Close(); writeStream.Close(); } public Action<string> OnSucessGettingPhotoFileName { get; set; } public Action<Exception> OnError { get; set; } } [Serializable] [ComVisible(true)] public class PhotoStreamEventArgs : EventArgs { public Stream PictureStream { get; set; } public Action<string> OnSucessGettingPhotoFileName { get; set; } } } ```