簡體   English   中英

Xamarin 中的調用目標引發異常

[英]Exception has been thrown by the target of an invocation in Xamarin

這是代碼(運行這個看看有什么問題) => https://github.com/x0axz/CustomRenderer

在我的 Xamarin 應用程序中,有一個用於 Android 的自定義相機渲染器,它是通過MessagingCenter.Send<object>(this, "A");ViewModel調用的; .

它工作正常。 唯一的問題是,在第一頁它需要圖片,但是當我導航到另一個頁面時,還有另一個命令MessagingCenter.Send<object>(this, "A"); , 拍照,但這次它返回一個錯誤Camera is being used after Camera.release() was called

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

您必須取消訂閱 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);
            }
        }

主頁.xaml

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM