Nativescript: TabView with ScrollView and MapView crashes

Created on 8 Apr 2017  路  18Comments  路  Source: NativeScript/NativeScript

Which platform(s) does your issue occur on?

Only tested on Android.

Please provide the following version numbers that your issue occurs with:

Please tell us how to recreate the issue in as much detail as possible.

I have a TabView with three tabs: the first one with a ScrollView, the second one with a MapView, and the third one empty. When the application is first launched it works fine, but if I minimize it and then resume, it crashes as soon as I switch between the tabs.

Sample code: https://github.com/ludcila/tabview-scrollview-mapview
(set API key in app/App_Resources/Android/values/nativescript_google_maps_api.xml)

D/AndroidRuntime(15596): Shutting down VM
W/dalvikvm(15596): threadid=1: thread exiting with uncaught exception (group=0x41f35700)
D/dalvikvm(15596): GC_FOR_ALLOC freed 1595K, 23% free 14306K/18456K, paused 22ms, total 22ms
W/System.err(15596): com.tns.NativeScriptException:
W/System.err(15596): Calling js method instantiateItem failed
W/System.err(15596): Error: java.lang.ClassCastException: android.view.AbsSavedState$1 cannot be cast to org.nativescript.widgets.HorizontalScrollView$SavedState
W/System.err(15596): org.nativescript.widgets.VerticalScrollView.onRestoreInstanceState(VerticalScrollView.java:166)
W/System.err(15596): android.view.View.dispatchRestoreInstanceState(View.java:13188)
W/System.err(15596): android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2850)
W/System.err(15596): android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2856)
W/System.err(15596): android.view.View.restoreHierarchyState(View.java:13166)
W/System.err(15596): com.tns.Runtime.callJSMethodNative(Native Method)
W/System.err(15596): com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1197)
W/System.err(15596): com.tns.Runtime.callJSMethodImpl(Runtime.java:1061)
W/System.err(15596): com.tns.Runtime.callJSMethod(Runtime.java:1047)
W/System.err(15596): com.tns.Runtime.callJSMethod(Runtime.java:1028)
W/System.err(15596): com.tns.Runtime.callJSMethod(Runtime.java:1018)
W/System.err(15596): com.tns.gen.android.support.v4.view.PagerAdapter_frnal_ts_helpers_l58_c38__PagerAdapterClassInner.instantiateItem(android.support.v4.view.PagerAdapter.java)
W/System.err(15596): android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1001)
W/System.err(15596): android.support.v4.view.ViewPager.populate(ViewPager.java:1183)
W/System.err(15596): android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:666)
W/System.err(15596): android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:628)
W/System.err(15596): android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:609)
W/System.err(15596): org.nativescript.widgets.TabLayout$TabClickListener.onClick(TabLayout.java:406)
W/System.err(15596): android.view.View.performClick(View.java:4475)
W/System.err(15596): android.view.View$PerformClick.run(View.java:18786)
W/System.err(15596): android.os.Handler.handleCallback(Handler.java:730)
W/System.err(15596): android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err(15596): android.os.Looper.loop(Looper.java:137)
W/System.err(15596): android.app.ActivityThread.main(ActivityThread.java:5419)
W/System.err(15596): java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(15596): java.lang.reflect.Method.invoke(Method.java:525)
W/System.err(15596): com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
W/System.err(15596): com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
W/System.err(15596): dalvik.system.NativeStart.main(Native Method)
W/System.err(15596): File: "file:///data/data/org.nativescript.tabs/files/app/tns_modules/tns-core-modules/ui/tab-view/tab-view.js, line: 64, column: 38
W/System.err(15596): StackTrace:
W/System.err(15596): Frame: function:'PagerAdapterClassInner.instantiateItem', file:'file:///data/data/org.nativescript.tabs/files/app/tns_modules/tns-core-modules/ui/tab-view/tab-view.js', line: 64, column: 39
W/System.err(15596): at com.tns.Runtime.callJSMethodNative(Native Method)
W/System.err(15596): at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1197)
W/System.err(15596): at com.tns.Runtime.callJSMethodImpl(Runtime.java:1061)
W/System.err(15596): at com.tns.Runtime.callJSMethod(Runtime.java:1047)
W/System.err(15596): at com.tns.Runtime.callJSMethod(Runtime.java:1028)
W/System.err(15596): at com.tns.Runtime.callJSMethod(Runtime.java:1018)
W/System.err(15596): at com.tns.gen.android.support.v4.view.PagerAdapter_frnal_ts_helpers_l58_c38__PagerAdapterClassInner.instantiateItem(android.support.v4.view.PagerAdapter.java)
W/System.err(15596): at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1001)
W/System.err(15596): at android.support.v4.view.ViewPager.populate(ViewPager.java:1183)
W/System.err(15596): at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:666)
W/System.err(15596): at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:628)
W/System.err(15596): at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:609)
W/System.err(15596): at org.nativescript.widgets.TabLayout$TabClickListener.onClick(TabLayout.java:406)
W/System.err(15596): at android.view.View.performClick(View.java:4475)
W/System.err(15596): at android.view.View$PerformClick.run(View.java:18786)
W/System.err(15596): at android.os.Handler.handleCallback(Handler.java:730)
W/System.err(15596): at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err(15596): at android.os.Looper.loop(Looper.java:137)
W/System.err(15596): at android.app.ActivityThread.main(ActivityThread.java:5419)
W/System.err(15596): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(15596): at java.lang.reflect.Method.invoke(Method.java:525)
W/System.err(15596): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
W/System.err(15596): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
W/System.err(15596): at dalvik.system.NativeStart.main(Native Method)
W/System.err(15596): Caused by: java.lang.ClassCastException: android.view.AbsSavedState$1 cannot be cast to org.nativescript.widgets.HorizontalScrollView$SavedState
W/System.err(15596): at org.nativescript.widgets.VerticalScrollView.onRestoreInstanceState(VerticalScrollView.java:166)
W/System.err(15596): at android.view.View.dispatchRestoreInstanceState(View.java:13188)
W/System.err(15596): at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2850)
W/System.err(15596): at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2856)
W/System.err(15596): at android.view.View.restoreHierarchyState(View.java:13166)
W/System.err(15596): ... 24 more
I/Process (15596): Sending signal. PID: 15596 SIG: 9

android

Most helpful comment

Here is a workaround for an Angular2 project, but it can be easily ported to a JavaScript project:

app/App_Resources/Android/values/ids.xml: <- create this file

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="scroll_view" type="id" />
</resources>

my-page.component.html:

<ScrollView (loaded)="onScrollViewLoaded($event)">
    <!-- Other views... -->
</ScrollView>

my-page.component.ts:

import * as utils from 'utils/utils';

@Component({
    moduleId: module.id,
    templateUrl: './my-page.component.html'
})
export class MyPageComponent {

    onScrollViewLoaded(event) {
        const scrollView = event.object;
        if (scrollView.android) {
            const id = utils.ad.resources.getId('scroll_view');
            scrollView.android.setId(id);
        }
    }

    ...
}

I've ran into a similar issue before.

All 18 comments

Hey, @ludcila thanks for the test project!

The issue is fully reproducible with all API levels using this sample

Steps to reproduce:

  • run the app
  • interact with the tabs (everything is OK!)
  • minimize the application and then go back
  • interact with the tabs and crash occurs immediately or after few tabs
Error: java.lang.ClassCastException: android.view.AbsSavedState$1 cannot be cast to org.nativescript.widgets.HorizontalScrollView$SavedState

I get just about the same error when using the back button on Android when the page going back to is with the mapView and Listview

java.lang.ClassCastException: android.view.AbsSavedState$1 cannot be cast to org.nativescript.widgets.HorizontalScrollView$SavedState
05-07 12:16:06.060  4878  4878 V JS      :      at org.nativescript.widgets.VerticalScrollView.onRestoreInstanceState(VerticalScrollView.java:166)
05-07 12:16:06.060  4878  4878 V JS      :      at android.view.View.dispatchRestoreInstanceState(View.java:15633)
05-07 12:16:06.060  4878  4878 V JS      :      at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3268)
05-07 12:16:06.060  4878  4878 V JS      :      at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3274)
05-07 12:16:06.060  4878  4878 V JS      :      at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3274)
05-07 12:16:06.060  4878  4878 V JS      :      at android.view.View.restoreHierarchyState(View.java:15611)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.Fragment.restoreViewState(Fragment.java:645)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1016)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1171)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.BackStackRecord.popFromBackStack(BackStackRecord.java:1747)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1691)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.FragmentManagerImpl$3.run(FragmentManager.java:586)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1578)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.FragmentManagerImpl$1.run(FragmentManager.java:483)
05-07 12:16:06.060  4878  4878 V JS      :      at android.os.Handler.handleCallback(Handler.java:751)
05-07 12:16:06.060  4878  4878 V JS      :      at android.os.Handler.dispatchMessage(Handler.java:95)
05-07 12:16:06.060  4878  4878 V JS      :      at android.os.Looper.loop(Looper.java:154)
05-07 12:16:06.060  4878  4878 V JS      :      at android.app.ActivityThread.main(ActivityThread.java:6077)
05-07 12:16:06.060  4878  4878 V JS      :      at java.lang.reflect.Method.invoke(Native Method)
05-07 12:16:06.060  4878  4878 V JS      :      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
05-07 12:16:06.060  4878  4878 V JS      :      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

This issue is fixed in NativeScript 3.0.0
Test application with modules 3.0.0 here

I am seeing the error mentioned above in NS 3.1.2 . when using the android back button when the page going back to is a mapview / scrollview.

Here is the error again for clarification: android.view.AbsSavedState$1 cannot be cast to org.nativescript.widgets.HorizontalScrollView$SavedState

@NickIliev App still crashes if I have a map view as descendant of scrollview, with tns android runtime 3.1.1 and nativescript-google-maps-sdk 2.1.3 Any workaround?

The issue mut be reopened, please fix it.

Regards

Having a map view inside a scroll view still crashes with android runtime v3.1.1. I ended up moving the map view to a popup in my app.

I have no a MapView Inside ScrollView

Hi @manojdcoder @isaacfi,
I tested this case while using the nativescritp-google-maps-sdk plugin and latest tns-core-modules 3.1.0 and the app seems to work as expected. I am attaching a sample project. it would help if you could review the project and to make the needed changes, which will allow us to investigate this problem.
Archive.zip

@tsonevn It doesn't crash as soon map is loaded inside scrollview. But does when a new page / activity is opened and you come back to the previous map activity. I will work on a sample where you can reproduce this and revert to you shortly.

@tsonevn Please find the attached sample project where you can easily reproduce the crash.

MapIssue.zip

Hi @manojdcoder,
Thank you for the sample app.
I will review it and will provide more info about the case.

Here is a workaround for an Angular2 project, but it can be easily ported to a JavaScript project:

app/App_Resources/Android/values/ids.xml: <- create this file

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="scroll_view" type="id" />
</resources>

my-page.component.html:

<ScrollView (loaded)="onScrollViewLoaded($event)">
    <!-- Other views... -->
</ScrollView>

my-page.component.ts:

import * as utils from 'utils/utils';

@Component({
    moduleId: module.id,
    templateUrl: './my-page.component.html'
})
export class MyPageComponent {

    onScrollViewLoaded(event) {
        const scrollView = event.object;
        if (scrollView.android) {
            const id = utils.ad.resources.getId('scroll_view');
            scrollView.android.setId(id);
        }
    }

    ...
}

I've ran into a similar issue before.

@tsonevn Can you please re-open this issue or create new one?

Reopening the issue - repro project in this comment.

It seems that Google MapView internally sets ids that are not unique and collide with id of our widgets. Once widgets save their state in order to later restore it their state get overridden by the internal widgets of MapView. So in order to prevent this crash you should call in createNativeView:

MapView.prototype.createNativeView = function () {
...
    this.nativeView.setSaveFromParentEnabled(false);

This will disable state saving for MapView and will stop this crash. After that another crash will happen but it is caused by the plugin itself - Marker class changes its android property and later when activity is recreated a crash will happen when .addMarker method is called. This needs refactoring inside the plugin code in order to be fixed.

If you want so save/restore map state it will be possible to attach handler to application launch event and get the saveInstanceState bundle from the event args (after this PR is merged https://github.com/NativeScript/NativeScript/pull/4750).

Then in onActivitySaveInstanceState you can save the map state like that:

this.nativeView.setSaveFromParentEnabled(true);
var mapState = new android.os.Bundle();
this.nativeView.onSaveInstanceState(mapState);
// Put the map bundle in the main outState
args.bundle.putBundle("mapData" + this._domId, mapState);
this.nativeView.setSaveFromParentEnabled(false);

and in application.launch handler to extract the bundle:

function MapView() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this._markers = new Array();
        application.on("launch", function (args) {
            var bundle = args.savedInstanceState;
            _this.savedInstanceState = bundle ? bundle.getBundle("mapData" + _this._domId) : null;
        });
        return _this;
    }

and finally in createNativeView you will be able to pass the bundle to create method:

MapView.prototype.createNativeView = function () {
...
this.nativeView = new com.google.android.gms.maps.MapView(this._context, options);
this.nativeView.setSaveFromParentEnabled(false);
this.nativeView.onCreate(this.savedInstanceState);
this.savedInstanceState = null;

And the plugin author should not update camera position always because this will break state restoration.

Hey!
I have a workaround for people who are facing crashes with the map view
https://shiv19.github.io/how-to-fix-nativescript-google-maps-sdk-map-view-crash-inside-scroll-view/

Hope this helps someone 馃槃

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings