nativescript-community/ui-material-components

[BottomSheet] - java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.fragment.app.FragmentTransaction'

vanishdark opened this issue · 9 comments

  • CLI: 8.3.3
  • Cross-platform modules: 8.3.5
  • ui-material-core - 7.0.28
  • BottomSheet - 7.0.28

This error pops up in the android emulator and physical only, in iOS everything works fine and as expected. I'm using the component BottomSheet and the component with the same options/settings works on 2 pages but doesn't work on 1 page.

The error catch is

Error: java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.fragment.app.FragmentTransaction androidx.fragment.app.FragmentTransaction.add(androidx.fragment.app.Fragment, java.lang.String)' on a null object reference

This is the code where the error is pop-up

const firstOrg = value.organisations[0].id; // value is 10
    const options: VueBottomSheetOptions = {
      dismissOnBackgroundTap: true,
      dismissOnDraggingDownSheet: false,
      ignoreBottomSafeArea: true,
      transparent: true,
      props: {
        selected: firstOrg, // First organisation on the list goes here;
      },
    };
    (this as unknown as NativeScriptVue)
      .$showBottomSheet(UserOrganisationSelectionVue, options)
      .then((value) => {
        const obj: ITCUserConfiguration = {
          organisation: value.id,
          role: value.role_id,
          permissions: null,
        };
        const permission = PermissionsService.getPermissionsByRoleId(
          value.role_id
        );
        obj.permissions = permission;
        const model = new TCUserConfiguration(obj);
        UserService.updateUserConfigurations(model);
        this.finishAuth();
      })
      .catch((e) => {
        console.log('Popup Organisations: ', e);
        this.finishAuth();
      });

And this is the same showBottomSheet calling the same component but without the error

const options: VueBottomSheetOptions = {
      dismissOnBackgroundTap: true,
      dismissOnDraggingDownSheet: false,
      ignoreBottomSafeArea: true,
      transparent: true,
      props: {
        selected: this.organisationSelected, // value is 10
      },
    };
    console.log(UserOrganisationSelectionVue);
    (this as unknown as NativeScriptVue)
      .$showBottomSheet(UserOrganisationSelectionVue, options)
      .then((value) => {
        this.organisationSelected = value.id;
        this.currentOrganisation = value;
        if (this.currentOrganisation.role_id) {
          this.role = PermissionsService.getRoleById(
            this.currentOrganisation.role_id
          );
          const obj: ITCUserConfiguration = {
            organisation: value.id,
            role: value.role_id,
            permissions: null,
          };
          const permission = PermissionsService.getPermissionsByRoleId(
            value.role_id
          );
          obj.permissions = permission;
          const model = new TCUserConfiguration(obj);
          UserService.createUserConfigurations(model);
        }
      })
      .catch((e) => {
        console.log(e);
      });

I did some search an saw similar issues but no solution and the workaround with a timeout didn't work for me

@vanishdark please share the full callstack and error

Hey @farfromrefug. There is no stack, only the error that I put above. that is printed in the catch from the showBottomSheet

JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(StackLayout(267), Label(269))
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateElement(button)
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateTextNode(Login)
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(Button(270), TextNode(null))
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(StackLayout(267), Button(270))
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(FlexboxLayout(266), StackLayout(267))
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(Page(265), FlexboxLayout(266))
  JS: [auth0 credentials] Fri Oct 28 2022 11:20:17 GMT+0100 (BST)
  JS: isAuthenticated true
  JS: function VueComponent (options) {
  JS:       this._init(options);
  JS:     }
  JS: USER ORGANISATION SELECTION CREATED
  JS: 10
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateElement(gridlayout)
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateComment()
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(GridLayout(271), Placeholder(272))
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateComment()
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(GridLayout(271), Placeholder(273))
  JS: USER ORGANISATION SELECTION MOUNTED
  JS: Error: java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.fragment.app.FragmentTransaction androidx.fragment.app.FragmentTransaction.add(androidx.fragment.app.Fragment, java.lang.String)' on a null object reference
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateElement(Page)
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateElement(gridlayout)
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateElement(stacklayout)

This is all I got. I got the error because I put the console.log inside the catch.
If it exists a better way to catch this please let me know, because I could not figure out how to.

UserOrganisationSelectionVue

<template>
  <GridLayout
    id="UserOrganisationSelection"
    rows="auto, auto, *"
    columns="auto, *, auto"
    class="bg-eggshell-white rounded-xl"
    @loaded="onLoadGrid"
  >
    <StackLayout row="0" col="2" margin="0" v-if="items.length">
      <Button
        class="text-lg text-dark-purple"
        padding="0"
        margin="10"
        @tap="onSelect"
        >Select</Button
      >
    </StackLayout>
    <ListPicker
      v-if="items.length"
      row="1"
      col="0"
      colSpan="3"
      verticalAlignment="middle"
      horizontalAlignment="middle"
      :items="items"
      v-model="picker"
      marginTop="0"
      marginRight="30"
      marginLeft="30"
      marginBottom="30"
    />
  </GridLayout>
</template>

<script lang="ts">
import { EventData, GridLayout } from '@nativescript/core';
import NativeScriptVue from 'nativescript-vue';
import { Component, Prop, Vue } from 'vue-property-decorator';
import { TCUser } from '~/models/tc.models/TCUser.model';
import {
  ModalStorageService,
  UserService,
} from '~/services/GlobalService.service';

@Component
export default class extends Vue {
  @Prop({ default: () => 0 }) selected: number;
  picker: any = null;
  items: any[] = [];

  created() {
    console.log('USER ORGANISATION SELECTION CREATED');
    console.log(this.selected);
  }
  mounted() {
    console.log('USER ORGANISATION SELECTION MOUNTED');
  }
  onLoadGrid(args: EventData): void {
    console.log('ON LOAD GRID USER ORGANISATION SELECTION');
    const view = args.object as GridLayout;
    ModalStorageService.save(view);
    const user = new TCUser(UserService.getCurrentUser());
    this.items = user.organisations.map((x: any) => x.name);
    this.picker = user.organisations.findIndex(
      (x: any) => x.id === this.selected
    );
  }
  onSelect(args: EventData) {
    const user = new TCUser(UserService.getCurrentUser());
    (this as unknown as NativeScriptVue).$closeBottomSheet(
      user.organisations[this.picker]
    );
  }
}
</script>

<style scoped></style>

Hey @farfromrefug I did a deep debug here is what i found.

code that is throw the error

df.show(parent._getRootFragmentManager(), domId.toString());
// both this._rootManager and this._context are null when the error is throw but the other pages that use the bottomShee the context has value
_getRootFragmentManager() {
        if (!this._rootManager && this._context) {
            this._rootManager = this._context.getSupportFragmentManager();
        }
        return this._rootManager;
    }

error message

"java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.fragment.app.FragmentTransaction androidx.fragment.app.FragmentTransaction.add(androidx.fragment.app.Fragment, java.lang.String)' on a null object reference"

stack

"_showNativeBottomSheet(file:///data/data/com.truecompliance.go/files/app/vendor.js:2841:12)
	at showBottomSheet(file:///data/data/com.truecompliance.go/files/app/vendor.js:2621:18)
	at (file:///data/data/com.truecompliance.go/files/app/vendor.js:2895:33)
	at Vue.$showBottomSheet(file:///data/data/com.truecompliance.go/files/app/vendor.js:2884:20)
	at generateConfigurations(file:///data/data/com.truecompliance.go/files/app/bundle.js:6729:14)
	at (file:///data/data/com.truecompliance.go/files/app/bundle.js:6708:22)
	at invoke(file:///data/data/com.truecompliance.go/files/app/vendor.js:16781:26)
	at run(file:///data/data/com.truecompliance.go/files/app/vendor.js:16785:13)
"

stacktrace

"_showNativeBottomSheet(file:///data/data/com.truecompliance.go/files/app/vendor.js:2841:12)
	at showBottomSheet(file:///data/data/com.truecompliance.go/files/app/vendor.js:2621:18)
	at (file:///data/data/com.truecompliance.go/files/app/vendor.js:2895:33)
	at Vue.$showBottomSheet(file:///data/data/com.truecompliance.go/files/app/vendor.js:2884:20)
	at generateConfigurations(file:///data/data/com.truecompliance.go/files/app/bundle.js:6729:14)
	at (file:///data/data/com.truecompliance.go/files/app/bundle.js:6708:22)
	at invoke(file:///data/data/com.truecompliance.go/files/app/vendor.js:16781:26)
	at run(file:///data/data/com.truecompliance.go/files/app/vendor.js:16785:13)
	androidx.fragment.app.DialogFragment.show(DialogFragment.java:276)
	com.tns.Runtime.callJSMethodNative(Native Method)
	com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1302)
	com.tns.Runtime.callJSMethodImpl(Runtime.java:1188)
	com.tns.Runtime.callJSMethod(Runtime.java:1175)
	com.tns.Runtime.callJSMethod(Runtime.java:1153)
	com.tns.Runtime.callJSMethod(Runtime.java:1149)
	com.tns.gen.java.lang.Runnable.run(Runnable.java:17)
	android.os.Handler.handleCallback(Handler.java:938)
	android.os.Handler.dispatchMessage(Handler.java:99)
	android.os.Looper.loopOnce(Looper.java:201)
	android.os.Looper.loop(Looper.java:288)
	android.app.ActivityThread.main(ActivityThread.java:7839)
	java.lang.reflect.Method.invoke(Native Method)
	com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
"

@vanishdark thanks. Did you enable source maps? Cause right now it points to vendor and I don't know where it points to in the original source.
Please either reproduce with source map or look at the vendor code and tell me where it points to.

@farfromrefug Yep, the source map is enabled. But the message returns the android files. I take a PrintScreen of the vs code with the file stack. You can see in the picture the stack trace message return the android files but the vscode debug stack shows the real files. Do you think this helps?

image
image

I did a manual search and these are the files

_showNativeBottomSheet (@nativescript-community/ui-material-bottomsheet/bottomsheet.android.js:196)
showBottomSheet (@nativescript-community/ui-material-bottomsheet/bottomsheet-common.js:101)
(anonymous function) (@nativescript-community/ui-material-bottomsheet/vue/index.js:30)
Vue.$showBottomSheet (@nativescript-community/ui-material-bottomsheet/vue/index.js:19)
generateConfigurations (Authentication.vue:103) // my vue component
(anonymous function) (Authentication.vue:82) // my vue component
invoke (@nativescript/core/timer/index.android.js:18)
run (@nativescript/core/timer/index.android.js:22)

@vanishdark thanks a lot i see much better now. So it seems your issue is that parent your showing the bottomsheet from is not yet created/initialised. By that i mean the (this as unknown as NativeScriptVue) in your code.
Cant tell you much more but if this._context it means the view(not the vue view, the N view ) is either not created yet or destroyed

@farfromrefug do you have any suggestions to fix this? I found in the logs before the error pop up

{NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> ParentNode(Placeholder(455)) -> null
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> NextSibling(Placeholder(455)) -> null
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateElement(gridlayout)
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateComment()
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(GridLayout(456), Placeholder(457))
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> CreateComment()
  JS: {NSVue (Vue: 2.6.14 | NSVue: 2.9.3)} -> AppendChild(GridLayout(456), Placeholder(458))
  JS: Error: java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.fragment.app.FragmentTransaction androidx.fragment.app.FragmentTransaction.add(androidx.fragment.app.Fragment, java.lang.String)' on a null object reference

You can see the parentNode is null but I have no placeholder anywhere in this 2 vue components
Do you think is related?

@vanishdark sorry very hard to tell without the full context.
if you can reproduce the issue in a simple example (vue is perfect) i will fix it

@farfromrefug I found out what is the issue.
So to authenticate the user a browser window is open inside the app. I remove that step and the bottomshet start working. I will do a workaround on this since I can't remove the authentication 😂