Xamarin中的调用目标已引发异常 [英] Exception has been thrown by the target of an invocation in Xamarin

查看:53
本文介绍了Xamarin中的调用目标已引发异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是代码(运行此代码以查看问题所在) => https://github.com/x0axz/CustomRenderer

在我的Xamarin应用程序中,有一个用于Android的自定义相机渲染器,它是通过 MessagingCenter从 ViewModel 调用的./code>.

In my Xamarin App, there is a Custom Camera Renderer for Android, which is being called from ViewModel through MessagingCenter.Send<object>(this, "A");.

一切正常.唯一的问题是,它在第​​一页上显示图片,但是当我导航到另一页时,还有另一个命令 MessagingCenter.Send< object>(this,"A"); ,以拍摄照片,但这一次它返回错误在调用Camera.release()之后正在使用相机.

It's working fine. The only problem is that, on first page it takes Picture, but when I navigate to another page, where there is an other command, MessagingCenter.Send<object>(this, "A");, to take a Picture, but this time it returns an error Camera is being used after Camera.release() was called.

下面是ViewModel和Camera Renderer的代码.

Below is the code for ViewModel and Camera Renderer.

FirstCameraViewModel.cs

private void FirstCamera(object sender, EventArgs e)
{
    try
    {
        MessagingCenter.Send<object>(this, "A");
    }
    catch
    {
        Console.WriteLine(error.InnerException.StackTrace);
        Console.WriteLine(error.InnerException.Message);
    }
    finally
    {
        timer_countdown = new Timer();
        timer_countdown.Interval = 1000;
        timer_countdown.Elapsed += OnTimedEvent;
        timer_countdown.Enabled = true;
        timer_countdown.AutoReset = true;
        timer_countdown.Start();
    }
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Seconds++;

    if (Seconds == 5)
    {
        MainThread.BeginInvokeOnMainThread(async () =>
        {
            await NavigationService.NavigateToAsync<SecondCameraViewModel>();
        });
    }
}

SecondCameraViewModel.cs,在此页面中返回错误

private void SecondCamera(object sender, EventArgs e)
{
    try
    {
        MessagingCenter.Send<object>(this, "A");
    }
    catch
    {
        Console.WriteLine(error.InnerException.StackTrace);
        Console.WriteLine(error.InnerException.Message);
    }
    finally
    {
        timer_countdown = new Timer();
        timer_countdown.Interval = 1000;
        timer_countdown.Elapsed += OnTimedEvent;
        timer_countdown.Enabled = true;
        timer_countdown.AutoReset = true;
        timer_countdown.Start();
    }
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Seconds++;

    if (Seconds == 5)
    {
        MainThread.BeginInvokeOnMainThread(async () =>
        {
            await NavigationService.NavigateToAsync<IndexViewModel>();
        });
    }
}

更新

CameraPreview.cs

public sealed class CameraPreview : ViewGroup, ISurfaceHolderCallback, Camera.IPictureCallback
{
    SurfaceView surfaceView;
    ISurfaceHolder holder;
    Camera.Size previewSize;
    IList<Camera.Size> supportedPreviewSizes;
    Camera camera;
    IWindowManager windowManager;

    public bool IsPreviewing { get; set; }

    public Camera Preview
    {
        get { return camera; }
        set
        {
            camera = value;
            if (camera != null)
            {
                supportedPreviewSizes = Preview.GetParameters().SupportedPreviewSizes;
                RequestLayout();
            }
        }
    }

    public CameraPreview(Context context)
        : base(context)
    {
        surfaceView = new SurfaceView(context);
        AddView(surfaceView);

        windowManager = Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();

        IsPreviewing = false;
        holder = surfaceView.Holder;
        holder.AddCallback(this);

        MessagingCenter.Subscribe<object>(this, "A", (e) =>
        {
            camera.TakePicture(null, null, this);
        });
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int width = ResolveSize(SuggestedMinimumWidth, widthMeasureSpec);
        int height = ResolveSize(SuggestedMinimumHeight, heightMeasureSpec);
        SetMeasuredDimension(width, height);

        if (supportedPreviewSizes != null)
        {
            previewSize = GetOptimalPreviewSize(supportedPreviewSizes, width, height);
        }
    }

    protected override void OnLayout(bool changed, int l, int t, int r, int b)
    {
        var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
        var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);

        surfaceView.Measure(msw, msh);
        surfaceView.Layout(0, 0, r - l, b - t);
    }

    public void SurfaceCreated(ISurfaceHolder holder)
    {
        try
        {
            if (Preview != null)
            {
                Preview.SetPreviewDisplay(holder);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(@"           ERROR: ", ex.Message);
        }
    }

    public void SurfaceDestroyed(ISurfaceHolder holder)
    {
        if (Preview != null)
        {
            Preview.StopPreview();
        }
    }

    public void SurfaceChanged(ISurfaceHolder holder, Android.Graphics.Format format, int width, int height)
    {
        var parameters = Preview.GetParameters();
        parameters.SetPreviewSize(previewSize.Width, previewSize.Height);
        RequestLayout();

        switch (windowManager.DefaultDisplay.Rotation)
        {
            case SurfaceOrientation.Rotation0:
                camera.SetDisplayOrientation(90);
                break;
            case SurfaceOrientation.Rotation90:
                camera.SetDisplayOrientation(0);
                break;
            case SurfaceOrientation.Rotation270:
                camera.SetDisplayOrientation(180);
                break;
        }

        Preview.SetParameters(parameters);
        Preview.StartPreview();
        IsPreviewing = true;
    }

    Camera.Size GetOptimalPreviewSize(IList<Camera.Size> sizes, int w, int h)
    {
        const double AspectTolerance = 0.1;
        double targetRatio = (double)w / h;

        if (sizes == null)
        {
            return null;
        }

        Camera.Size optimalSize = null;
        double minDiff = double.MaxValue;

        int targetHeight = h;
        foreach (Camera.Size size in sizes)
        {
            double ratio = (double)size.Width / size.Height;

            if (Math.Abs(ratio - targetRatio) > AspectTolerance)
                continue;
            if (Math.Abs(size.Height - targetHeight) < minDiff)
            {
                optimalSize = size;
                minDiff = Math.Abs(size.Height - targetHeight);
            }
        }

        if (optimalSize == null)
        {
            minDiff = double.MaxValue;
            foreach (Camera.Size size in sizes)
            {
                if (Math.Abs(size.Height - targetHeight) < minDiff)
                {
                    optimalSize = size;
                    minDiff = Math.Abs(size.Height - targetHeight);
                }
            }
        }

        return optimalSize;
    }

    public void OnPictureTaken(byte[] data, Camera camera)
    {
        camera.StopPreview();

        FileOutputStream outStream = null;
        File dataDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim);
        if (data != null)
        {
            try
            {
                TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                var s = ts.TotalMilliseconds;
                outStream = new FileOutputStream(dataDir + "/" + s + ".jpg");
                outStream.Write(data);

                outStream.Close();
            }
            catch (FileNotFoundException e)
            {
                System.Console.Out.WriteLine(e.Message);
            }
            catch (IOException ie)
            {
                System.Console.Out.WriteLine(ie.Message);
            }
        }
        camera.StartPreview();
    }
}

CameraPreviewRenderer.cs

public class CameraPreviewRenderer : ViewRenderer<Mobile.App.CameraPreview, CameraPreview>
{
    CameraPreview cameraPreview;

    public CameraPreviewRenderer(Context context) : base(context)
    {
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Mobile.App.CameraPreview> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            // Unsubscribe
            cameraPreview.Click -= OnCameraPreviewClicked;
        }
        if (e.NewElement != null)
        {
            if (Control == null)
            {
                cameraPreview = new CameraPreview(Context);
                SetNativeControl(cameraPreview);
            }
            Control.Preview = Camera.Open((int)e.NewElement.Camera);

            // Subscribe
            cameraPreview.Click += OnCameraPreviewClicked;
        }
    }

    void OnCameraPreviewClicked(object sender, EventArgs e)
    {
        if (cameraPreview.IsPreviewing)
        {
            cameraPreview.Preview.StopPreview();
            cameraPreview.IsPreviewing = false;
        }
        else
        {
            cameraPreview.Preview.StartPreview();
            cameraPreview.IsPreviewing = true;
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            Control.Preview.Release();
        }
        base.Dispose(disposing);
    }
}

推荐答案

您将必须取消订阅MessagingCenter.

You will have to Unsubscribe the MessagingCenter.

共享项目中的CameraPreview.cs

CameraPreview.cs in shared project

public event EventHandler Subscribe;
        public event EventHandler Unsubscribe;

        public void OnSubscribe()
        {
            if (Subscribe != null)
            {
                Subscribe(this, EventArgs.Empty);
            }
        }
        public void OnUnsubscribe()
        {
            if (Unsubscribe != null)
            {
                Unsubscribe(this, EventArgs.Empty);
            }
        }

MainPage.xaml

MainPage.xaml

<local:CameraPreview Camera="Rear" x:Name="CameraPreview"  HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />

MainPage.xaml.cs

MainPage.xaml.cs

protected override void OnAppearing()
        {
            base.OnAppearing();
            CameraPreview.OnSubscribe();
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();
            CameraPreview.OnUnsubscribe();
        }

FirstCameraPage.xaml

FirstCameraPage.xaml

<local:CameraPreview x:Name="CameraPreview"
                        Camera="Rear" 
                        HorizontalOptions="CenterAndExpand" 
                        VerticalOptions="FillAndExpand" 
                        WidthRequest="250"/>

FirstCameraPage.xaml.cs

FirstCameraPage.xaml.cs

protected override void OnAppearing()
        {
            base.OnAppearing();
            CameraPreview.OnSubscribe();
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();
            CameraPreview.OnUnsubscribe();
        }

android项目中的CameraViewRenderer.cs

CameraViewRenderer.cs in android project

protected override void OnElementChanged(ElementChangedEventArgs<CustomRenderer.CameraPreview> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                // Unsubscribe
                cameraPreview.Click -= OnCameraPreviewClicked;
            }
            if (e.NewElement != null)
            {
                if (Control == null)
                {
                    cameraPreview = new CameraPreview(Context);
                    SetNativeControl(cameraPreview);
                }
                Control.Preview = Camera.Open();
                e.NewElement.Subscribe += (sender, e) =>
                {
                    Control.Subscribe();
                };
                e.NewElement.Unsubscribe += (sender, e) =>
                {
                    Control.Unsubscribe();
                };

                // Subscribe
                cameraPreview.Click += OnCameraPreviewClicked;
            }
        }

Android项目中的CameraPreview.cs,添加以下方法.

CameraPreview.cs in android project, Add below methods.

internal void Subscribe()
        {
            MessagingCenter.Subscribe<object>(this, "A", (e) =>
            {
                this.Preview.TakePicture(null, null, this);
            });
        }

        internal void Unsubscribe()
        {
            MessagingCenter.Unsubscribe<object>(this, "A");
        }

并从构造函数中删除MessagingCenter订阅

and remove MessagingCenter subscription from constructor

public CameraPreview (Context context)
            : base (context)
        {
            surfaceView = new SurfaceView (context);
            AddView (surfaceView);

            windowManager = Context.GetSystemService (Context.WindowService).JavaCast<IWindowManager> ();

            IsPreviewing = false;
            holder = surfaceView.Holder;
            holder.AddCallback (this);

            //MessagingCenter.Subscribe<object>(this, "A", (e) =>
            //{
            //  this.Preview.TakePicture(null, null, this);
            //});
        }

这篇关于Xamarin中的调用目标已引发异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆