iOS Monotouch UIImagePickerController 从相机拍摄多张照片/视频

3
我们的UIImagePickerController出现了奇怪的问题。在我们的应用程序中,用户可以填写一系列表格,并在这些表格内附加图像和视频。
我们允许用户从相机胶卷中添加多个照片/视频,或者在填写表单时拍摄多个照片/视频。
我们使用UIImagePickerController来完成此操作。当使用相机拍摄1或2张图像/视频时,问题就会发生。
当第三次重新进入相机屏幕时,图像就变成静态状态,不再更新。视图停留在最后一帧被捕获的内容上。
如果按下捕捉按钮,则图像/视频会突然更新,并捕捉到相机所指向的内容。从那时起,选择器再次表现正常。此外,从相机胶卷中选择图片/视频似乎可以使所有内容再次表现正常。最后,在屏幕不响应并且用户选择拍照时,视图会缩小到视图内的一个小矩形。控制器的设置如下:
    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;
    }

一个captureEvent的例子如下:
    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);
    }

目前,正如您所看到的,我们没有保留对选择器的引用。但是,我们尝试了存储对选择器的引用并在CopyData方法后释放它的代码变化,我们在copydata之后并在dispose之前添加了picker.Release()(导致显示后续选择器崩溃应用程序),以及几乎所有其他主题的变化。
有没有人知道为什么会发生这种情况以及如何解决它?我的假设是我们的内存可能不足,但是每次处理/仅创建一个实例并将其模式从图片更改为视频都没有任何影响,我们总是看到相同的行为。
编辑
感谢Kento和下面的答案,我们需要做的就是类似于以下内容才能使其按预期工作:
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);
    }
}

获取一张图片:
    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);
    }

获取视频的方法如下:
    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);
    }

你好,我遇到了同样的问题。我使用了MvvmCross图片选择器插件,并查看了他们的源代码,发现他们使用了delegate,但是我的应用程序仍然存在问题。你能指导我吗? - SoftSan
@Sudhir3 我建议您发布一个带有一些示例代码和您已经尝试过的内容的问题。 - user1455942
谢谢,我已经在这里发布了我的问题:http://stackoverflow.com/questions/21642912/mvvmcross-picturechoosen-plugin-and-camera-stuck-issue - SoftSan
2个回答

5

我之前也遇到了这个问题。

虽然这篇帖子没有被标记为答案,但是它对我有用: https://dev59.com/rHfZa4cB1Zd3GeqPWdA-#20035698

我猜这可能是使用FinishedPickingMedia事件时MonoTouch的一个bug。我已经看到使用UIImagePickerController会出现泄漏的情况(无论是使用obj c还是Mono),所以我更喜欢保留实例并重复使用它。如果您每次都重新创建它,我建议处理掉以前的实例。

能否由Xamarin的任何人权衡一下这是否是一个bug?


非常感谢您的回答,这正是我需要做的。我将编辑我的问题,并附上我编写的代码,以便使其按照预期工作。 - user1455942
赞同。我们遇到了同样的问题。从事件(Event)切换到委托(Delegate)后,问题消失了。谢谢。 - schmidiii
你好,我遇到了同样的问题。我使用了MvvmCross图片选择器插件,并查看了他们的源代码,发现他们使用了delegate,但是我的应用程序仍然存在问题。你能指导我吗? - SoftSan

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接