【问题标题】:Exception has been thrown by the target of an invocation in XamarinXamarin 中的调用目标已引发异常
【发布时间】:2021-03-08 17:53:00
【问题描述】:

这里是代码(运行这个看看有什么问题) => https://github.com/x0axz/CustomRenderer

在我的 Xamarin 应用程序中,有一个适用于 Android 的自定义相机渲染器,从 ViewModelMessagingCenter.Send<object>(this, "A"); 调用它。

一切正常。唯一的问题是,在第一页上它会拍照,但是当我导航到另一个页面时,有另一个命令 MessagingCenter.Send<object>(this, "A"); 来拍照,但这一次它返回一个错误 Camera is being在调用 Camera.release() 之后使用

下面是 ViewModel 和 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);
    }
}

【问题讨论】:

    标签: c# android .net xamarin xamarin.forms


    【解决方案1】:

    您必须取消订阅 MessagingCenter。

    共享项目中的CameraPreview.cs

    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

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

    MainPage.xaml.cs

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

    FirstCameraPage.xaml

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

    FirstCameraPage.xaml.cs

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

    Android 项目中的CameraViewRenderer.cs

    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,添加以下方法。

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

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

    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);
                //});
            }
    

    【讨论】:

    • 非常感谢 :) 你太棒了!
    • 先生,这是一件事。我想在 FirstCameraPage 中启用 前置摄像头。早些时候我可以,但是在你的代码之后我无法启用.. 这是提交 => github.com/x0axz/CustomRenderer/commit/… .. 请看一下.. 在此先感谢 :)
    • 先生,您知道吗,为什么前置摄像头不工作?
    • Control.Preview = Camera.Open((int)e.NewElement.Camera);
    猜你喜欢
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 2021-12-27
    • 1970-01-01
    • 2019-01-22
    相关资源
    最近更新 更多