Home > Enterprise >  Xamarin NullReferenceException when calling 'Finish()' on activity
Xamarin NullReferenceException when calling 'Finish()' on activity

Time:06-07

I created a biometric authentication service that starts an activity and registers a callback to a static EventHandler for the result.

The handler:

public class BiometricHandler : IBiometricHandler
{
    private TaskCompletionSource<byte[]> taskCompletionSource;

    public Task<byte[]> StartBiometricAuth()
    {
        Intent intent = new Intent(Android.App.Application.Context, typeof(BiometricActivity));
        intent.AddFlags(ActivityFlags.NewTask);
        Android.App.Application.Context.StartActivity(intent);

        taskCompletionSource = new TaskCompletionSource<byte[]>();
        BiometricActivity.BiometricEventHandler  = BiometricCompleted;

        return taskCompletionSource.Task;
    }

    private void BiometricCompleted(object sender, BiometricEventArgs e)
    {
        taskCompletionSource.SetResult(e.Success ? e.Payload : new byte[] { });

        BiometricActivity.BiometricEventHandler -= BiometricCompleted;
    }
}

And the activity (not the actual code obviously):

public class BiometricActivity : Activity
{
    public static event EventHandler<BiometricEventArgs> BiometricEventHandler;
    private readonly int BIOMETRIC_REQUEST = 1;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        Intent intent = new Intent(Application.Context, typeof(BiometricAuth));
        StartActivityForResult(intent, BIOMETRIC_REQUEST);
    }

    protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
    {

        BiometricEventHandler?.Invoke(
            this,
            new BiometricEventArgs(
                true, new byte[] {1, 2, 3}
            );

        Finish();
        
    }
}

The above code throws a NullReferenceException:

0xFFFFFFFFFFFFFFFF in System.Diagnostics.Debugger.Mono_UnhandledException_internal
0x1 in System.Diagnostics.Debugger.Mono_UnhandledException at /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System.Diagnostics/Debugger.cs:125,4
0x20 in Android.Runtime.DynamicMethodNameCounter.57
0x6 in Xamarin.Forms.Platform.Android.PlatformConfigurationExtensions.OnThisPlatform<Xamarin.Forms.Application> at D:\a\_work\1\s\Xamarin.Forms.Platform.Android\PlatformConfigurationExtensions.cs:8,4
0xC in Xamarin.Forms.Platform.Android.AppCompat.FragmentContainer.OnResume at D:\a\_work\1\s\Xamarin.Forms.Platform.Android\AppCompat\FragmentContainer.cs:126,4
0x8 in AndroidX.Fragment.App.Fragment.n_OnResume at C:\a\_work\1\s\generated\androidx.fragment.fragment\obj\Release\monoandroid12.0\generated\src\AndroidX.Fragment.App.Fragment.cs:2570,4
0x11 in Android.Runtime.DynamicMethodNameCounter.57

And the console:

**System.NullReferenceException:** 'Object reference not set to an instance of an object.'

I narrowed it down to the Finish() method. There is no exception when it is not called.

I tried calling Finish() from the handler using BroadcastReceiver, same result.

Why does Finish() throw this exception?

CodePudding user response:

Well, it seems like the issue is an asynchronous race condition. Finish() takes a bit longer to complete than the service to return the data.

Then the content page tries to perform a UI event, and since Finish() hasn't finished yet, the activity is still "visible" and the content page is not yet responsible for the UI thread. So the UI event fails with the exception.

Since there doesn't seem to be an easy way to await the Finish() call, I used Task.Await to delay the UI event for a bit and to Finish() complete.

Not ideal, but at least NullReferenceException is gone

  • Related