To shorten the problem: I am developing an android application which requires users to log in, and since multiple users could be logged in at the same time, I want to cycle between the authenticated users using NFC touch cards. Everything works fine except after using ZXing.Mobile
bar-code scanner, when code returns from scanning any bar-code, and tries to push a page model, this particular exception is being thrown Java.Lang.IllegalStateException: Can not perform this action after onSaveInstanceState
. Please note that I am using Xamarin.Forms, FreshMVVM, ZXing.Mobile, and of course C#.
Fragments of code used:
AndroidManifest.xml:
<activity android:name="com.name.SplashActivity">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.MAIN" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/com.name.nfc" />
</intent-filter>
</activity>
<activity android:name="com.name.MainActivity">
</activity>
The above code is used to enable the application to launch using NFC tags. SplashActivity
launches MainActivity
.
SplashActivity.cs:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
StartActivity(typeof(MainActivity));
}
protected override void OnResume()
{
base.OnResume();
if (NfcAdapter.ActionNdefDiscovered == Intent.Action)
{
ProcessIntent(Intent);
}
}
protected override void OnNewIntent(Intent intent)
{
Intent = intent;
}
public void ProcessIntent(Intent intent)
{
//Code omitted to simplify the question.
}
Above code is shown just to know how I am using the NFC touch event.
Code to open the bar-code scanner from main page model:
public ICommand OpenCameraCommand => new Command(async () =>
{
IsAvailable = false;
((Command) OpenCameraCommand).ChangeCanExecute();
string checkBarcode = await _scanService.CameraScanAsync().ConfigureAwait(true);
if (!string.IsNullOrWhiteSpace(checkBarcode))
{
Barcode = checkBarcode;
}
IsAvailable = true;
}, () => IsAvailable);
From scan service:
public async Task<string> CameraScanAsync()
{
//AutoFocus code omitted to simplify the question
Result result = await _mobileBarcodeScanner.Scan(new MobileBarcodeScanningOptions { PossibleFormats = _listOfBarcodeFormats }).ConfigureAwait(false);
return result == null ? string.Empty : result.Text;
}
EDIT: code containing the push page model method:
switch (response.Status)
{
case Case.Second:
await CoreMethods.PushPageModel<SecondaryPageModel>(response).ConfigureAwait(true);
Barcode = string.Empty;
return;
case Case.Third:
await CoreMethods.PushPageModel<ThirdPageModel>(response).ConfigureAwait(true);
Barcode = string.Empty;
return;
case Case.Fourth:
await CoreMethods.PushPageModel<FourthPageModel>(response).ConfigureAwait(true);
Barcode = string.Empty;
return;
case Case.Invalid:
break;
default:
throw new InvalidOperationException();
}
This code is fired directly after returning from scanning a bar-code.
END EDIT
All of this works after the NFC card is being touched and the application launched, until hitting the next line of code. After a bar-code is returned from the scanner:
await CoreMethods.PushPageModel<SecondaryPageModel>(response).ConfigureAwait(true);
The exception is being thrown right here. I debugged my code to check what's going on. When the camera is open, it first fires MainActivity OnSaveInstanceState
event, after successfully scanning a bar-code, MainActivity OnResume
> MainActivity OnPostResume
events are fired in that order. Then the PushPageModel
method is called. Note that when I manually enter the bar-code in the relative field, everything works fine, it's just the scanner that throws this exception.
I have searched for solutions here in SO. I found some answers that says to opt-out the base.OnSaveInstanceState()
line, I tried that with no luck, another answer said to enter junk values to work around the issue, tried that with no luck as well. I tried different launch modes in the AndroidManifest file like singleTop
or singleTask
or singleInstance
with no luck as well.
I will be glad with any help that could be given. Thanks in advance.
MainActivity is running multiple instances when you are switching using NFC, Add to MainActivity LaunchMode as SingleTask, then when you launch using NFC clear the Task and create a new one. A good way to specify Activity flags is using Xamarin attributes, it is a better way than adding them in Manifest.xml