Bug 31688 - 'Navigation.InsertPageBefore()' does not work for more than two pages, "throws java.lang.IndexOutOfBoundsException: index=3 count=2"
Summary: 'Navigation.InsertPageBefore()' does not work for more than two pages, "throw...
Status: IN_PROGRESS
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms (show other bugs)
Version: 2.3.3
Hardware: All All
: Normal normal
Target Milestone: ---
Assignee: Rui Marinho
URL:
Depends on:
Blocks:
 
Reported: 2015-07-07 05:16 UTC by alemarko
Modified: 2017-10-09 16:44 UTC (History)
11 users (show)

See Also:
Tags: ac android navigation fr
Is this bug a regression?: ---
Last known good build:


Attachments
repro case (18.51 KB, application/octet-stream)
2015-07-07 05:16 UTC, alemarko
Details
Partial workaround (29.31 KB, application/octet-stream)
2015-07-10 03:19 UTC, alemarko
Details
repro case for Windows 8.1 (35.79 KB, application/octet-stream)
2015-07-16 09:37 UTC, alemarko
Details

Description alemarko 2015-07-07 05:16:33 UTC
Created attachment 11899 [details]
repro case

User can invoke method many times to insert pages,
but adding more than two pages messes up the navigation 
stack and the next invocation of 'Navigation.PopAsync()' throws Java exception on Android.


FATAL EXCEPTION: main
java.lang.IndexOutOfBoundsException: index=3 count=2
	at android.view.ViewGroup.addInArray(ViewGroup.java:3755)
	at android.view.ViewGroup.addViewInner(ViewGroup.java:3694)
	at android.view.ViewGroup.addView(ViewGroup.java:3543)
	at android.view.ViewGroup.addView(ViewGroup.java:3488)
	at mono.java.lang.RunnableImplementor.n_run(Native Method)
	at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:29)
	at android.os.Handler.handleCallback(Handler.java:615)
	at android.os.Handler.dispatchMessage(Handler.java:92)
	at android.os.Looper.loop(Looper.java:137)
	at android.app.ActivityThread.main(ActivityThread.java:4921)
	at java.lang.reflect.Method.invokeNative(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:511)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
	at dalvik.system.NativeStart.main(Native Method)





I attached a simple solution showing problem.

About the attached solution:
idea is to use method 'InsertPageBefore()' to restore application state as it was before the OS killed the app.
So after starting the app, first I add instance of 'ActitivityIndicatorPage' (showing spinning animation, named AIP) 
using 'Navigation.ShowAsync()', so it becomes second and last page in the navigation stack.
After that I insert the pages before AIP and after adding the last 'real' page,
I want to hide AIP with 'Navigation.PopAsync()' -> in this moment I get the exception.


Xamarin.Android Version: 5.1.4
Xamarin Studio Version 5.9.4 (build 5)
Android SDK compiler used: 5.0 (API 21)
Xamarin.Forms 1.4.3.6374 (same bug also in versions 1.3.5 and 1.4.2)


Tested on real Android devices (Android OS versions 4.1.2 and 5.0.1).
Comment 1 Udham Singh 2015-07-07 06:27:16 UTC
I have checked this issue with the help of sample app given in bug description and able to reproduce the reported behaviour.

Screencast : http://www.screencast.com/t/qwVhGfAf

Ide Logs : https://gist.github.com/Parmendrak/dec2d573a7cf1ea9368d
Application Output : https://gist.github.com/Parmendrak/232e34ce560e425d9603
Adb Logcat : https://gist.github.com/Parmendrak/62a2b2ead93af385bd52

Environment Info : 

Xamarin.Forms : 1.4.3.6374

=== Xamarin Studio ===

Version 5.9.4 (build 5)
Installation UUID: 1a096c6f-0678-402e-89b2-a2c10f7e80e4
Runtime:
	Mono 4.0.2 ((detached/c99aa0c)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 400020005

=== Apple Developer Tools ===

Xcode 6.2 (6776)
Build 6C131e

=== Xamarin.Mac ===

Version: 2.0.2.43 (Enterprise Edition)

=== Xamarin.iOS ===

Version: 8.10.2.43 (Enterprise Edition)
Hash: 428e4d4
Branch: master
Build date: 2015-07-03 10:41:01-0400

=== Xamarin.Android ===

Version: 5.1.4.16 (Enterprise Edition)
Android SDK: /Users/360_macmini/Desktop/android-sdk-macosx
	Supported Android versions:
		2.3    (API level 10)
		4.0.3  (API level 15)
		4.1    (API level 16)
		4.2    (API level 17)
		4.3    (API level 18)
		4.4    (API level 19)
		4.4.87 (API level 20)
		5.0    (API level 21)
Java SDK: /usr
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)

=== Xamarin Android Player ===

Version: Unknown version
Location: /Applications/Xamarin Android Player.app

=== Build Information ===

Release ID: 509040005
Git revision: 8010a90f6e246b32364e3fb46ef2c9d1be9c9a2b
Build date: 2015-06-08 16:52:06-04
Xamarin addins: 7e93e9c3503f28770f23ce1b7eafd829919f18e8

=== Operating System ===

Mac OS X 10.9.4
Darwin ShrutiMac.local 13.3.0 Darwin Kernel Version 13.3.0
    Tue Jun  3 21:27:35 PDT 2014
    root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64
Comment 2 alemarko 2015-07-10 03:19:52 UTC
Created attachment 11967 [details]
Partial workaround

I found a partial workaround (zipped solution is attached),
but it causes different problem so it's still makes apps unusable: 
THERE IS NO WAY TO RESTORE NAVIGATION PAGE STACK!

But I hope this workaround may give you some clue about what is the 
real problem (I suspect animations).

Workaround: to hide the page with activity indicator, I used
the method 'Navigation.PopAsync()' with method parameter set to 'false'.

MyApp.cs  line 50:
'await Navigation.PopAsync();' became 'await Navigation.PopAsync(false);'

This will enable all pages to be displayed and now we are the 'Page 3'.


New begins a new problem: 'Navigation.PushAsync()' works, but page
we navigate to does not dislay any content anymore.


Steps to reproduce new problem:

1. open app: it will navigate to 'Page 3' which contains one label
(navigation stack: MyMainPage -> Page1 -> Page2 -> Page3).

2. tap on the "Back" button on toolbar to close 'Page3'

3. now on 'Page 2' tap on the button 'Show Page 3' to display Page 3 again.

4. 'Page 3' is displayed without any content, only toolbar - children 
area is blank (there should be one label with text 'Page 3')
Comment 3 alemarko 2015-07-10 03:26:24 UTC
There is a similar bug reported (31077) about blank pages after 
manipulating navigation stack using 'RemovePage' and 'InsertPageBefore'.

https://bugzilla.xamarin.com/show_bug.cgi?id=31077
Comment 4 alemarko 2015-07-16 09:37:14 UTC
Created attachment 12070 [details]
repro case for Windows 8.1

I see that the same problem with blank pages exists on desktop Windows 8.1
(difference is that on Windows blank pages appear always, ).

What I noticed on both Android and Windows: blank pages appear only if one 
page is closed with 'PopAsync' - if user closes more than one page (let's say Page3 and Page2) -> now opening a new with 'ShowAsync' works.

Another issue on Windows only: pages initally created with InsertPageBefore don't display toolbar with back arrow and page title. Toolbar appears only
on MyMainPage after we close all the other pages by clicking "Close" buttons. After we get back to starting page, toolbar will be visible in pages after clicking "Open page X". 


How to produce problematic behaviour: same as in "Comment 2":

1. open app: it will navigate to 'Page 3' which contains one label
(navigation stack: MyMainPage -> Page1 -> Page2 -> Page3).

2. tap on the "Back" button on toolbar to close 'Page3'

3. now on 'Page 2' tap on the button 'Show Page 3' to display Page 3 again.

4. 'Page 3' is displayed without any content, only toolbar - children 
area is blank (there should be one label with text 'Page 3')
Comment 5 alemarko 2015-07-16 12:20:14 UTC
CORRECTION: I made an error above - toolbar is visible on Windows 8.1, but BACK button is missing from the toolbar.
Comment 6 Jimmy [MSFT] 2016-12-16 18:19:20 UTC
Crash still occurring on Android with Forms 2.3.3 using the repro project provided.

Stack trace from Android project: https://gist.github.com/jimmgarrido/f4c213c3f991cc3947040206f45ae4fc
Comment 7 David Dunscombe 2017-02-01 21:17:16 UTC
the pop with animation exception issue is to do with SwitchContentAsync in NavigationRenderer.cs

Specifically:

// animate out
if (containerToAdd.Parent != this)
	AddView(containerToAdd, ((IElementController)Element).LogicalChildren.IndexOf(rendererToAdd.Element));
else
	((IPageController)rendererToAdd.Element).SendAppearing();

The problem is that when you do InsertPageBefore there are now multiple LogicalChildren that do not have any associated page renderers. However the index that is derived from that is used in the AddView method, which is excepting an index of child page renderers.

I found changing the above AddView to the following:

AddView(containerToAdd, ChildCount-1);

works but i'm unsure as to the full implications.
Comment 8 Roy Cornelissen 2017-08-22 07:17:31 UTC
We're running into this in our project too. Using Xamarin.Forms 2.3.4.247, so it's been around for a long time. Definitely deserves some attention.
Comment 9 Rui Marinho 2017-10-04 17:52:26 UTC
Workaround is simple just move to FormsAppCompatActivity, crash doesn't happen there but we are looking at the issue.

Note You need to log in before you can comment on or make changes to this bug.