Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] UI Freeze and 'Cannot Access a Disposed Object' Error While Continuously Scanning Barcodes or Repeatedly Scanning a Single Barcode #40

Open
HaileyKim04 opened this issue Dec 23, 2024 · 15 comments
Assignees
Labels
bug Something isn't working platform/android

Comments

@HaileyKim04
Copy link

Description

This issue arises when scanning a single barcode for an extended period, when the camera stops functioning after multiple scans, or when switching between barcode scanning and unrelated screens (e.g., a barcode image or any random background)**

Steps to Reproduce

  1. Navigate to a page containing CameraView.
  2. Scan a barcode.
  3. Switch back and forth between barcode scanning and unrelated screens multiple times.
  4. The issue manifests as the camera freezing or stopping after several repeated cycles.

Expected Behavior

  • The camera should continue functioning without freezing or stopping, regardless of the duration of scanning or repeated interactions with unrelated pages/screens.

Actual Behavior

  • The camera stops working or freezes.
  • Error thrown: Cannot access a disposed object. Object name: 'AndroidX.Camera.View.Transform.CoordinateTransform'.

Basic Information

  • Version with issue: 1.4.19
  • Last known good version:

Screenshots, Attachments, Links

Cannot access a disposed object. Object name: 'AndroidX.Camera.View.Transform.CoordinateTransform'.

@HaileyKim04 HaileyKim04 added the bug Something isn't working label Dec 23, 2024
@HaileyKim04
Copy link
Author

HaileyKim04 commented Jan 2, 2025

Hello @thomasgalliker , In the context of BarcodeAnalyze under Android codebase, the current implementation catches exceptions and log it

catch (Exception ex)
{
    this.logger.LogError(ex, "Analyze failed with exception");
}

I’m wondering if this supposed to be throwing the exception

@thomasgalliker
Copy link
Owner

Thanks for reporting this issue. I have to look at it.
Regarding the catched exception: the code snipped bit out of context. In some situations it‘s totally fine to catch and not rethrow the exception.

@thomasgalliker
Copy link
Owner

@HaileyKim04 are you using AppShell or classic navigation? If you find the time to create a small repro app which causes this issue, I‘d be very happy.

@HaileyKim04
Copy link
Author

HaileyKim04 commented Jan 8, 2025

Yes, I am using classic navigation. This is the repository, and I noticed that scanning stops after scanning several barocdes in the repository.

MauiApp1.zip

@Magnuskeel
Copy link

Hi , just want to say amazing barcode scanning control, unfortunately I am having the same issue:

CameraScanner.Maui.BarcodeAnalyzer: Error: Analyze failed with exception

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'AndroidX.Camera.View.Transform.CoordinateTransform'.
at Java.Interop.JniPeerMembers.AssertSelf(IJavaPeerable self) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs:line 153
at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 39
at AndroidX.Camera.View.Transform.CoordinateTransform.MapRect(RectF rect) in D:\a_work\1\s\generated\androidx.camera.camera-view\obj\Release
et8.0-android\generated\src\AndroidX.Camera.View.Transform.CoordinateTransform.cs:line 112
at CameraScanner.Maui.Platforms.Services.BarcodeScanner.ProcessBarcodeResult(Object inputResults, HashSet1 outputResults, CoordinateTransform transform) in C:\Users\mkoso\source\repos\CameraScanner.Maui\Platforms\Android\Services\BarcodeScanner.cs:line 111 at CameraScanner.Maui.CameraManager.PerformBarcodeDetectionAsync(IImageProxy proxy) in C:\Users\mkoso\source\repos\CameraScanner.Maui\Platforms\Android\CameraManager.cs:line 404 at CameraScanner.Maui.Utils.SyncHelper.RunOnceAsync(Func1 task) in C:\Users\mkoso\source\repos\CameraScanner.Maui\Utils\SyncHelper.cs:line 19
at CameraScanner.Maui.BarcodeAnalyzer.Analyze(IImageProxy proxyImage) in C:\Users\mkoso\source\repos\CameraScanner.Maui\Platforms\Android\BarcodeAnalyzer.cs:line 62
[0:] CameraScanner.Maui.BarcodeAnalyzer: Error: Analyze -> IImageProxy.Close failed with exception

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'AndroidX.Camera.Core.SettableImageProxy'.
at Java.Interop.JniPeerMembers.AssertSelf(IJavaPeerable self) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.cs:line 153
at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 57
at AndroidX.Camera.Core.ForwardingImageProxy.Close()
at CameraScanner.Maui.BarcodeAnalyzer.Analyze(IImageProxy proxyImage) in C:\Users\mkoso\source\repos\CameraScanner.Maui\Platforms\Android\BarcodeAnalyzer.cs:line 88

I am using AppShell navigation

@thomasgalliker
Copy link
Owner

Thanks for reporting 👍🏻 I'm currently bit in pre-release stress but I'm positive we can solve this.

@thomasgalliker
Copy link
Owner

Is it possible to reproduce with the sample app in this repository? Or can anyone create a super-small sample app which causes this issue?

@Magnuskeel
Copy link

Not sure yet but might have found a fix, when i am confident its actually working consistently I can show you what I did. Prolly a threading issue.

@Magnuskeel
Copy link

I think because the Analyze method was set to async void along with this line

var run = await this.syncHelper.RunOnceAsync(() => this.cameraManager.PerformBarcodeDetectionAsync(proxyImage));

you were getting a race condition.

if you remove the async from the method signature and wrap that above line of code a Task.Run like this:

Task.Run(async () =>
{
    var run = await this.syncHelper.RunOnceAsync(() => this.cameraManager.PerformBarcodeDetectionAsync(proxyImage));

    if (run == false)
    {
        // this.logger.LogDebug("Analyze -> frame skipped (already in progress)");
    }
}).Wait();   

The problem seems to stop happening.

so the entire method looks like this.

```

public void Analyze(IImageProxy proxyImage)
{

    try
    {                   

        if (this.PauseScanning)
        {
            return;
        }

        if (this.BarcodeDetectionFrameRate is not uint r || r is 0u or 1u || this.skippedFrames == null || ++this.skippedFrames >= r)
        {
            // this.logger.LogDebug("Analyze");

            if (this.cameraManager.CaptureNextFrame)
            {
                this.cameraManager.CaptureImage(proxyImage);
            }
            else
            {
                Task.Run(async () =>
                {
                    var run = await this.syncHelper.RunOnceAsync(() => this.cameraManager.PerformBarcodeDetectionAsync(proxyImage));

                    if (run == false)
                    {
                        // this.logger.LogDebug("Analyze -> frame skipped (already in progress)");
                    }
                }).Wait();                        
            }

            if (this.BarcodeDetectionFrameRate != null)
            {
                this.skippedFrames = 0;
            }
        }
        else
        {
            // this.logger.LogDebug("Analyze -> frame skipped (BarcodeDetectionFrameRate)");
        }
    }
    catch (Exception ex)
    {
        this.logger.LogError(ex, "Analyze failed with exception");
    }
    finally
    {
        try
        {
            if(proxyImage != null)
                proxyImage.Close();
        }
        catch (Exception ex)
        {
            this.logger.LogError(ex, "Analyze -> IImageProxy.Close failed with exception");
             MainThread.BeginInvokeOnMainThread(() => this.cameraManager.StartAsync());
        }                
    }            
}

}


And there doesnt seem to be a performance hit. Do with it what you will :)

@haeun159951
Copy link

haeun159951 commented Feb 12, 2025

Is it possible to reproduce with the sample app in this repository? Or can anyone create a super-small sample app which causes this issue?

Yes, I could reproduce this error in the sample demo app.

One strange thing is I cannot reproduce the issue in sample as long as the library Project is referenced in the Sample project.
If I remove the library project reference and add the Nuget version, no matter which version, try the latest, pre-release, and 1.3 as well, I can reproduce the issue in the sample project.

I used the QR code scanner page and ViewModel to edit the code.

Steps to produce:

  1. Create one barcode using the barcode generator website
  2. Scan a barcode and Keep scrolling up and down fast
  3. after 2-3 mins, try to check logs to see the exception in console tab

Image

**QrCodeScannerPage.xaml** 
 
<c:CameraView
            Grid.Row="0"
            CameraEnabled="{Binding IsScannerEnabled}"
            OnDetectionFinishedCommand="{Binding OnDetectionFinishedCommand}"/>

        <Label BackgroundColor="White" 
               TextColor="Black"
               WidthRequest="200" Height="80" Text="{Binding ScannedText}"/>

**QrCodeScannerViewModel.cs**
 
   private async Task HandleScanResultAsync(BarcodeResult[] barcodeResults)
        {
            try
            {
                if (barcodeResults.FirstOrDefault() is BarcodeResult barcodeResult)
                {
                    // this.IsScannerPause = true;
                    //
                    // var stop = await this.dialogService.DisplayAlertAsync(
                    //     "Barcode found",
                    //     $"BarcodeType=\"{barcodeResult.BarcodeType}\"{Environment.NewLine}" +
                    //     $"BarcodeFormat=\"{barcodeResult.BarcodeFormat}\"{Environment.NewLine}" +
                    //     $"DisplayValue=\"{barcodeResult.DisplayValue}\"",
                    //     "Stop", "Continue");
                    //
                    // if (stop)
                    // {
                    //     this.StopCamera();
                    // }
                    // else
                    // {
                    //     this.IsScannerPause = false;
                    // }

                    this.ScannedText = barcodeResult.DisplayValue;
                }
            }

@haeun159951
Copy link

haeun159951 commented Feb 12, 2025

I think because the Analyze method was set to async void along with this line

var run = await this.syncHelper.RunOnceAsync(() => this.cameraManager.PerformBarcodeDetectionAsync(proxyImage));

you were getting a race condition.

if you remove the async from the method signature and wrap that above line of code a Task.Run like this:

Task.Run(async () =>
{
    var run = await this.syncHelper.RunOnceAsync(() => this.cameraManager.PerformBarcodeDetectionAsync(proxyImage));

    if (run == false)
    {
        // this.logger.LogDebug("Analyze -> frame skipped (already in progress)");
    }
}).Wait();   

The problem seems to stop happening.

so the entire method looks like this.


public void Analyze(IImageProxy proxyImage) {

try
{                   

    if (this.PauseScanning)
    {
        return;
    }

    if (this.BarcodeDetectionFrameRate is not uint r || r is 0u or 1u || this.skippedFrames == null || ++this.skippedFrames >= r)
    {
        // this.logger.LogDebug("Analyze");

        if (this.cameraManager.CaptureNextFrame)
        {
            this.cameraManager.CaptureImage(proxyImage);
        }
        else
        {
            Task.Run(async () =>
            {
                var run = await this.syncHelper.RunOnceAsync(() => this.cameraManager.PerformBarcodeDetectionAsync(proxyImage));

                if (run == false)
                {
                    // this.logger.LogDebug("Analyze -> frame skipped (already in progress)");
                }
            }).Wait();                        
        }

        if (this.BarcodeDetectionFrameRate != null)
        {
            this.skippedFrames = 0;
        }
    }
    else
    {
        // this.logger.LogDebug("Analyze -> frame skipped (BarcodeDetectionFrameRate)");
    }
}
catch (Exception ex)
{
    this.logger.LogError(ex, "Analyze failed with exception");
}
finally
{
    try
    {
        if(proxyImage != null)
            proxyImage.Close();
    }
    catch (Exception ex)
    {
        this.logger.LogError(ex, "Analyze -> IImageProxy.Close failed with exception");
         MainThread.BeginInvokeOnMainThread(() => this.cameraManager.StartAsync());
    }                
}            

}


}

And there doesnt seem to be a performance hit. Do with it what you will :)

I usually get these three exceptions very quickly in logs, but after applying this code, they are now hard to reproduce. No UI freezing issue so far.

Exceptions:

Cannot access a disposed object. Object name: 'AndroidX.Camera.Core.SettableImageProxy'.
Cannot access a disposed object. Object name: 'AndroidX.Camera.View.Transform.CoordinateTransform'.

Would it be possible to create a PR for this fix and publish a new version?

@thomasgalliker
Copy link
Owner

Ok. I gonna have a look at this code. On which devices did you have the UI freezes?

@haeun159951
Copy link

Ok. I gonna have a look at this code. On which devices did you have the UI freezes?

I’ve tried two different devices: a Samsung S21 and an A15. Sometimes, I can reproduce the UI freeze, but not always. Also, the scanning stopped working, and I got the exception: 'Cannot access a disposed object. Object name: 'AndroidX.Camera.Core.SettableImageProxy'

@decv86
Copy link

decv86 commented Feb 14, 2025

@thomasgalliker Despite the bugs, this is the best plugin at the moment. Thanks for your work!

@thomasgalliker
Copy link
Owner

We‘re using this plugin in production apps. And yes we also experience the ObjectDisposedException. Sadly there are even worse problems I have to care about. I‘ll come back to this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working platform/android
Projects
None yet
Development

No branches or pull requests

5 participants