Forum Xamarin.Forms

Xamarin.Forms.NavigationProxy.PopAsync: System.ArgumentOutOfRangeException: Index was out of range.

Hello,

I recently got that curious exception in my Xamarin App on iOS. I currently struggle to symbolicate it properly in HockeyApp but anyway here is the crash reporter log from HA:

Hardware Model: iPhone4,1
Process: trucker_rolspedi [625]
Path: /var/containers/Bundle/Application/B028371C-62B4-4BCD-8491-C78EFE825D22/trucker_rolspediOS.app/trucker_rolspediOS
Identifier: com.rolsped.TruckerApp
Version: 1.1 (60)
Code Type: ARM
Parent Process: ??? [1]

Date/Time: 2016-12-04T04:53:09Z
Launch Time: 2016-12-04T04:46:07Z
OS Version: iPhone OS 9.3.5 (13G36)
Report Version: 104-Xamarin

Exception Type: SIGABRT
Exception Codes: #0 at 0x21efec5c
Crashed Thread: 0

Application Specific Information:
*** Terminating app due to uncaught exception 'System.ArgumentOutOfRangeException', reason: 'System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.'

Xamarin Exception Stack:
Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) <0x384df0 + 0x00040> in <15e850188d9f425bbeae90f0bbc51e17#ddbdd0f52c53581cb2d9c691bfe34183>:0
at System.ThrowHelper.ThrowArgumentOutOfRangeException () <0x384b68 + 0x0001b> in <15e850188d9f425bbeae90f0bbc51e17#ddbdd0f52c53581cb2d9c691bfe34183>:0
at System.Collections.Generic.List`1[T].get_Item (System.Int32 index) <0x24a68c + 0x0002f> in <15e850188d9f425bbeae90f0bbc51e17#ddbdd0f52c53581cb2d9c691bfe34183>:0
at Xamarin.Forms.NavigationProxy.Pop () <0x5678b4 + 0x00047> in <f9095492ed2b43559d0236ac22ab7223#ddbdd0f52c53581cb2d9c691bfe34183>:0
at Xamarin.Forms.NavigationProxy.OnPopAsync (System.Boolean animated) <0x567518 + 0x0005b> in <f9095492ed2b43559d0236ac22ab7223#ddbdd0f52c53581cb2d9c691bfe34183>:0
at Xamarin.Forms.NavigationProxy.PopAsync (System.Boolean animated) <0x56708c + 0x0002f> in <f9095492ed2b43559d0236ac22ab7223#ddbdd0f52c53581cb2d9c691bfe34183>:0
at trucker_rolsped.Pages.Media.TaskPhotoUploadPage+d__9.MoveNext () <0xe86944 + 0x013bf> in <3fbc044b4d76429b8dee1ec91e769c22#ddbdd0f52c53581cb2d9c691bfe34183>:0

Here the Code from the root cause Stacktrace line. It must happen at the await Navigation.PopAsync(animated: false)statement:

       private async void SendMediaOnClicked(object sender, EventArgs e)
        {
            SendMedia.IsEnabled = false;

            try
            {
                SelectedMedia.DokArt = _dokArt;
                SelectedMedia.TruckAppId = _truckAppId;

                UserDialogs.Instance.ShowLoading("Foto wird hochgeladen...");

                await AzureBlobStorageManager.Instance.UploadMediaAsync(SelectedMedia);

                UserDialogs.Instance.HideLoading();

                switch (SelectedMedia.MediaState)
                {
                    case MediaState.Uploaded:

                        if (IsTakenPhoto)
                        {
                            var result = await DisplayAlert("Foto Upload", "Foto wurde erfolgreich hochgeladen. Möchten Sie das Foto jetzt vom Handy löschen?", "Ja", "Nein");

                            if (result)
                            {
                                //Platform specific file delete
                                var truckerappMedia = SelectedMedia.File.Path;

                                var platformFileHandler = DependencyService.Get<IFileHandling>();

                                if (platformFileHandler != null)
                                    if (await platformFileHandler.FileExistsAsync(truckerappMedia))
                                    {
                                        var deleted = await platformFileHandler.DeleteFileAsync(truckerappMedia);

                                        if (deleted)
                                            UserDialogs.Instance.Toast("Foto wurde erfolgreich hochgeladen und am Handy gelöscht!!", TimeSpan.FromSeconds(value: 2));

                                        else
                                            UserDialogs.Instance.Toast("Foto konnte nicht gelöscht werden! Falls Sie das Foto nicht benötigen " +
                                                                               "bitte in der Fotogallery selbst löschen", TimeSpan.FromSeconds(value: 5));

                                    }
                            }
                        }
                        else
                            UserDialogs.Instance.Toast("Upload erfolgreich!", TimeSpan.FromSeconds(value: 2));


                        break;
                    case MediaState.Queued:
                        UserDialogs.Instance.Toast("Upload erfolgt automatisch wenn Sie wieder mit Internet oder dem mobilem Netz verbunden sind!");
                        break;
                    case MediaState.Created:
                        await DisplayAlert("Media Info", "Upload MediaState.Created!", "Ok");
                        break;
                    case MediaState.Error:
                        await DisplayAlert("Media Info", "Upload MediaState.Error!", "Ok");
                        break;
                    default:
                        await DisplayAlert("Media Info", "Upload MediaState Unknown!", "Ok");
                        break;
                }
            }
            catch (Exception ex)
            {
                SelectedMedia.MediaState = MediaState.Error;
                await DisplayAlert("Sende Media Fehler", ex.Message, "Ok");
            }
            finally
            {
                if (SelectedMedia.MediaState == MediaState.Uploaded)
                {
                    SelectedMedia?.Dispose();
                    SelectedMedia = null;
                }

                _workflowItem.TruckAuftragWorkFlow.TaskStatusId = 80;

                await Navigation.PopAsync(animated: false);
                _tcs.SetResult(true);
            }
        }

Here the 2 code areas where I instantiate and use the TakePhotoUploadPage:

1. Usage: From another page called Task40ActionPage

In **Task40ActionPage ** I invoke that method to show the TakePhotoUploadPage :

private async void RejectLoadInTimeClicked(object sender, EventArgs e)
{
    _workflowItem.TruckAuftragLauf.FlagFotoLadezeit = null;

    try
    {
        await ShowPhotoPageAsync(this, _workflowItem);
    }
    catch (Exception ex)
    {
        await MetricsManagerHelper.Instance.SendExceptionToApplicationInsights(ex);
    }

    await Navigation.PopAsync(animated: false);
    _tcs.SetResult(true);
}

public async Task<bool> ShowPhotoPageAsync(Page page, WorkflowItem workflowItem)
{
    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

    try
    {
        await Navigation.PushAsync(new TaskPhotoUploadPage(tcs, workflowItem, dokArt: "50"), animated: false);
    }
    catch (Exception e)
    {
        tcs.SetException(e);
    }

    return await tcs.Task;
}

2. Usage: From an ICommand Action delegate:

    public async Task Task50ActionAsync(WorkflowItem workflowItem)
    {
        bool isLastWorkItem = false;
        var page = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();

        try
        {
            if (workflowItem.QuestionYn)
            {
                if (page != null)
                    Device.BeginInvokeOnMainThread(
                        async () =>
                        {
                            try
                            {
                                bool isOk = await page.DisplayAlert("Todo Command", "Task50ActionAsync ausführen?", "Ja", "Nein");

                                if (isOk)
                                {
                                    await ShowPhotoPageAsync(page, workflowItem, dokArt: "60");

                                    UserDialogs.Instance.ShowLoading("Aufgabe wird gespeichert...", MaskType.Black);
                                    isLastWorkItem = await InnerTask50ActionAsync(workflowItem);

                                    //PUSH changes to remote.db
                                    await OfflineSyncStoreManager.Instance.PushAsync(OfflineSyncStoreManager.Instance.TruckAuftragWorkFlowTable.TableName);

                                    if (isLastWorkItem)
                                    {
                                        // Set TAL to completed
                                        workflowItem.TruckAuftragLauf.IsCompleted = true;

                                        // Pop Workflow UI View
                                        Device.BeginInvokeOnMainThread(async () => await page.Navigation.PopAsync(animated: false));
                                    }
                                    UserDialogs.Instance.HideLoading();
                                }
                            }
                            catch (Exception e)
                            {
                                await MetricsManagerHelper.Instance.SendExceptionToApplicationInsights(e);

                                Device.BeginInvokeOnMainThread(
                                    async () =>
                                    {
                                        await
                                            page.DisplayAlert("Todo Command Error",
                                                $"TaskId={workflowItem.TaskId} Action Error:{e}", "Ok");
                                    });
                            }
                        });
            }
            else
            {
                await ShowPhotoPageAsync(page, workflowItem, dokArt: "60");

                UserDialogs.Instance.ShowLoading("Aufgabe wird gespeichert...", MaskType.Black);
                isLastWorkItem = await InnerTask50ActionAsync(workflowItem);

                //PUSH changes to remote.db
                await OfflineSyncStoreManager.Instance.PushAsync(OfflineSyncStoreManager.Instance.TruckAuftragWorkFlowTable.TableName);

                if (isLastWorkItem)
                {
                    // Set TAL to completed
                    workflowItem.TruckAuftragLauf.IsCompleted = true;

                    // Pop Workflow UI View
                    Device.BeginInvokeOnMainThread(async () => await page.Navigation.PopAsync(animated: false));
                }
                UserDialogs.Instance.HideLoading();
            }
        }
        catch (Exception e)
        {
            await MetricsManagerHelper.Instance.SendExceptionToApplicationInsights(e);

            if (page != null)
                Device.BeginInvokeOnMainThread(
                    async () =>
                    {
                        await
                            page.DisplayAlert("Todo Command Error", $"TaskId={workflowItem.TaskId} Action Error:{e}",
                                "Ok");
                    });
        }
    }

    public async Task<bool> ShowPhotoPageAsync(Page page, WorkflowItem workflowItem, string dokArt)
    {
        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

        try
        {
            await page.Navigation.PushAsync(new TaskPhotoUploadPage(tcs, workflowItem, dokArt: dokArt), animated: false);
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }

        return await tcs.Task;
    }

Thanks to everyone with helpful suggestions in advance,

Eric

Answers

  • JessLpezJessLpez USMember ✭✭

    Hi Eric, did you find a solution?

  • EricBrunnerEricBrunner USMember ✭✭
    Nop. Have same issue on Android too. I currently check the NavStack Count and prevent PopAsync when NavStack is empty (for whatever reason).
  • RaymondKellyRaymondKelly USMember ✭✭✭

    I have the same issue. @EricBrunner can you explain how you are checking? This is crash is driving me crazy because I cannot reproduce it. Thanks.

  • EricBrunnerEricBrunner USMember ✭✭
    That way:

    // Sometimes NavStack.Count == 0. (XF bug)
    if (await IsNavStackInvalid())
    return;

    await Navigation.PopAsync(animated: false);


    private async Task<bool> IsNavStackInvalid()
    {
    int currentNavigationStackCount = Navigation.NavigationStack.Count;

    if (currentNavigationStackCount <= 1)
    {
    // see curious error: https://rink.hockeyapp.net/manage/apps/460391/app_versions/36/crash_reasons/165742824
    Dictionary<string, string> telemetryDictionary = new Dictionary<string, string>();
    List<string> pageStack = new List<string>();

    foreach (var page in Navigation.NavigationStack)
    {
    string pageClassName = page.GetType().Name;
    pageStack.Add(pageClassName);
    }

    telemetryDictionary.Add("pageStack", JsonConvert.SerializeObject(pageStack));

    await MetricsManagerHelper.Instance.SendGenericMessageToApplicationInsightsAsync(
    "Error-Task70PhotoUploadNavStack",
    $"Navigationstack Count == {currentNavigationStackCount}. User get automatically navigated back to TA Overview (root).", telemetryDictionary);

    await DisplayAlert(
    await LanguageMapper.Instance.GetTextAsync(LanguageMapping.TagAlertIntNaviErrorTitle),
    await LanguageMapper.Instance.GetTextAsync(LanguageMapping.TagAlertIntNaviErrorText),
    await LanguageMapper.Instance.GetTextAsync(LanguageMapping.TagAlertOk));

    _tcs.TrySetResult(false);
    return true;
    }
    return false;
    }
  • RaymondKellyRaymondKelly USMember ✭✭✭

    Thank you @EricBrunner . What is the behavior when the stack is empty? You still return to the previous page? Also, your code does not compile, List is missing the type e.g. List

  • EricBrunnerEricBrunner USMember ✭✭
    edited August 2017
    Currently I only log that issue, but you can try PopToRootView ( don't know if that works on corrupted NavStack)https://developer.xamarin.com/api/member/Xamarin.Forms.NavigationPage.PopToRootAsync()/
    I had that issue only on deployed apps running in the field and only on Android. Never on iOS. I personally never had that while development.
  • AhmedovAhmedovAhmedovAhmedov USMember ✭✭

    I just had the same problem. In my case it was caused my this line:

    await Navigation.PopToRootAsync();
    

    Resolved it like this:

    if (Navigation.NavigationStack.Count > 0)
    {
        await Navigation.PopToRootAsync();
    }
    
Sign In or Register to comment.