iOS Monotouch UIImagePickerController multiple pho

2019-02-19 00:47发布

问题:

We're experiencing a strange problem with a UIImagePickerController. In our application users are able to fill out a series of forms and also attach images and videos within these forms.

We allow users to add multiple photos / videos either from the camera roll or to be captured at the time of filling the form out.

We're using the UIImagePickerController to do this. The problem occurs when 1 or 2 images / videos are taken with the camera.

Once 1 or 2 images / videos are captured when the camera screen is re-entered for a third time the image is static and doesn't update. The view is stuck at the last frame of whatever was captured last.

If the capture button is pressed then the image / video suddenly updates and has captured what the camera was pointing at. From then on the picker is good for another go behaving normally. Additionally selecting a picture / video from the camera roll appears to make everything behave again for another picture / video. Finally when the screen isn't responding and the user has selected to take a picture the view will shrink to a small rectangle within the view. The controller is being setup as follows:

    private void SourceChosen(EventHandler<UIImagePickerMediaPickedEventArgs> captureEvent, int buttonIndex, string[] mediaTypes)
    {
        var picker = ConfigurePicker(mediaTypes, captureEvent);

        if (CameraAvailable && buttonIndex == 0)
        {
            picker.SourceType = UIImagePickerControllerSourceType.Camera;
            picker.CameraDevice = UIImagePickerControllerCameraDevice.Rear;
            this.NavigationController.PresentViewController(picker, true, () => { });
        }

        if ((!CameraAvailable && buttonIndex == 0) || (CameraAvailable && buttonIndex == 1))
        {
            picker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
            this.NavigationController.PresentViewController(picker, false, () => { });
        }
    }

    private UIImagePickerController ConfigurePicker(string[] mediaTypes, EventHandler<UIImagePickerMediaPickedEventArgs> captureEvent)
    {
        var mediaPicker = new UIImagePickerController();
        mediaPicker.FinishedPickingMedia += captureEvent;
        mediaPicker.Canceled += (sender, args) => mediaPicker.DismissViewController(true, () => { });
        mediaPicker.SetBarDefaults();
        mediaPicker.MediaTypes = mediaTypes;
        return mediaPicker;
    }

An example of a captureEvent is as follows:

    void PhotoChosen(object sender, UIImagePickerMediaPickedEventArgs e)
    {
        UIImage item = e.OriginalImage;
        string fileName = string.Format("{0}.{1}", Guid.NewGuid(), "png");
        string path = Path.Combine(IosConstants.UserPersonalFolder, fileName);
        NSData imageData = item.AsPNG();
        CopyData(imageData, path, fileName, ViewModel.Images, ((UIImagePickerController)sender));
    }

    private void CopyData(NSData imageData, string path, string fileName, List<AssociatedItem> collectionToAddTo, UIImagePickerController picker)
    {
        byte[] imageBytes = new byte[imageData.Length];
        System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, imageBytes, 0, Convert.ToInt32(imageData.Length));
        File.WriteAllBytes(path, imageBytes);

        AssociatedItem item = new AssociatedItem
        {
            StorageKey = fileName
        };

        collectionToAddTo.Add(item);
        picker.DismissViewController(true, ReloadTables);
    }

At the moment as you can see we're not holding a reference to the picker but we have tried variations of this code where we store a reference to the picker and dispose it after the CopyData method, we've added picker.Release(); after copydata and before the dispose (results in subsequent pickers crashing the application when displayed) and pretty much every other variation on the theme.

Does anyone have any idea why this might be occurring and how to fix it? It was my assumption that we might be running low on memory but neither disposing of it each time / only ever creating one instance and changing its mode from pictures to videos has any affect and we always see the same behaviour.

EDIT

Thanks to Kento and the below answer what we needed to get it all working as intended was something along the lines of:

public class PickerDelegate : UIImagePickerControllerDelegate
{
    private readonly Action<UIImagePickerController, NSDictionary> _captureEvent;

    public PickerDelegate(Action<UIImagePickerController, NSDictionary> captureEvent)
    {
        _captureEvent = captureEvent;
    }

    public override void FinishedPickingMedia(UIImagePickerController picker, NSDictionary info)
    {
        _captureEvent(picker, info);
    }
}

Then to get an image

    void PhotoChosen(UIImagePickerController picker, NSDictionary info)
    {
        UIImage item = (UIImage)info.ObjectForKey(UIImagePickerController.OriginalImage);
        string fileName = string.Format("{0}.{1}", Guid.NewGuid(), "png");
        string path = Path.Combine(IosConstants.UserPersonalFolder, fileName);
        NSData imageData = item.AsPNG();
        CopyData(imageData, path, fileName, ViewModel.Images, picker);
    }

Or to get a video

    void VideoChosen(UIImagePickerController picker, NSDictionary info)
    {
        var videoURL = (NSUrl)info.ObjectForKey(UIImagePickerController.MediaURL);
        NSData videoData = NSData.FromUrl(videoURL);
        string fileName = string.Format("{0}.{1}", Guid.NewGuid(), "mov");
        string path = Path.Combine(IosConstants.UserPersonalFolder, fileName);
        CopyData(videoData, path, fileName, ViewModel.Videos, picker);
    }

回答1:

I had this same problem.

The post here is not marked as the answer but it did solve it for me: https://stackoverflow.com/a/20035698/2514318

I'm guessing this is a bug w/ MonoTouch when using the FinishedPickingMedia event. I have read that there are leaks with using UIImagePickerController (regardless of using obj c or Mono) so I prefer to keep the instance around and re-use it. If you do re-create it each time, I would recommend disposing the previous instance.

Can anyone from Xamarin weigh in on if this is a bug or not?



回答2:

This post helped me a lot, so I decided to make a very simples sample and post on github for anyone that may need it: https://github.com/GiusepeCasagrande/XamarinSimpleCameraSample