Calling Java method from within Qt yields exception



  • I am trying to implement this example functionality within my application: https://doc.qt.io/qt-5/qtandroidextras-notification-example.html

    Here is my java class:

    package com.company.mri;
    
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.content.Context;
    
    public class NotificationClient extends org.qtproject.qt5.android.bindings.QtActivity
    {
        private static NotificationManager m_notificationManager;
        private static Notification.Builder m_builder;
        private static NotificationClient m_instance;
    
        public NotificationClient()
        {
            m_instance = this;
        }
    
        public static void notify(String title, String body)
        {
            if (m_notificationManager == null)
            {
                m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE);
                m_builder = new Notification.Builder(m_instance);
                m_builder.setSmallIcon(R.drawable.icon);
                m_builder.setContentTitle(title);
            }
    
            m_builder.setContentText(body);
            m_notificationManager.notify(1, m_builder.build());
        }
    }
    

    This is how I call it from within cpp:

    * @brief   Creates a notification in the Android OS top bar
     * @param   title: Message title text.
     * @param   body: message body.
     * @param   duration_s: this parameter is unused on this OS
     */
    void COsAndroid::showNotification(const QString& title,
                                      const QString& body,
                                      const int duration_s)
    {
        Q_UNUSED(duration_s)
    
        QAndroidJniObject andIniObjTitle = QAndroidJniObject::fromString(title);
        QAndroidJniObject andIniObjBody = QAndroidJniObject::fromString(body);
    
        QAndroidJniObject::callStaticMethod<void>(
                    "com/company/mri/NotificationClient",
                    "notify",
                    "(Ljava/lang/String;Ljava/lang/String;)V",
                    andIniObjTitle.object<jstring>(),
                    andIniObjBody.object<jstring>());
    
        qDebug() << "Android notification:" << title << body;
    }
    

    My problem is that my application crashes because of an exception from this call:

    F m.company.mr: java_vm_ext.cc:542] JNI DETECTED ERROR IN APPLICATION: JNI GetStaticMethodID called with pending exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object com.company.mri.NotificationClient.getSystemService(java.lang.String)' on a null object reference
    F m.company.mr: java_vm_ext.cc:542]   at void com.company.mri.NotificationClient.notify(java.lang.String, java.lang.String) (NotificationClient.java:72)
    F m.company.mr: java_vm_ext.cc:542]   at void org.qtproject.qt5.android.QtNative.startQtApplication() (QtNative.java:-2)
    F m.company.mr: java_vm_ext.cc:542]   at void org.qtproject.qt5.android.QtNative$7.run() (QtNative.java:387)
    F m.company.mr: java_vm_ext.cc:542]   at void org.qtproject.qt5.android.QtThread$1.run() (QtThread.java:61)
    F m.company.mr: java_vm_ext.cc:542]   at void java.lang.Thread.run() (Thread.java:764)
    F m.company.mr: java_vm_ext.cc:542]
    F m.company.mr: java_vm_ext.cc:542]     in call to GetStaticMethodID
    F m.company.mr: java_vm_ext.cc:542]     from void org.qtproject.qt5.android.QtNative.startQtApplication()
    F m.company.mr: java_vm_ext.cc:542] "qtMainLoopThread" prio=5 tid=13 Runnable
    F m.company.mr: java_vm_ext.cc:542]   | group="main" sCount=0 dsCount=0 flags=0 obj=0x12e80dc0 self=0xe456f800
    F m.company.mr: java_vm_ext.cc:542]   | sysTid=15364 nice=0 cgrp=default sched=0/0 handle=0xd27ff970
    F m.company.mr: java_vm_ext.cc:542]   | state=R schedstat=( 284579146 68957989 442 ) utm=19 stm=9 core=3 HZ=100
    F m.company.mr: java_vm_ext.cc:542]   | stack=0xd26fc000-0xd26fe000 stackSize=1042KB
    F m.company.mr: java_vm_ext.cc:542]   | held mutexes= "mutator lock"(shared held)
    F m.company.mr: java_vm_ext.cc:542]   native: #00 pc 004152f6  /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+198)
    F m.company.mr: java_vm_ext.cc:542]   native: #01 pc 0051048e  /system/lib/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) const+382)
    F m.company.mr: java_vm_ext.cc:542]   native: #02 pc 0050b743  /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) const+83)
    F m.company.mr: java_vm_ext.cc:542]   native: #03 pc 0031a8b0  /system/lib/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+1088)
    F m.company.mr: java_vm_ext.cc:542]   native: #04 pc 0031ad21  /system/lib/libart.so (art::JavaVMExt::JniAbortV(char const*, char const*, char*)+113)
    F m.company.mr: java_vm_ext.cc:542]   native: #05 pc 000d60f7  /system/lib/libart.so (art::(anonymous namespace)::ScopedCheck::AbortF(char const*, ...)+71)
    F m.company.mr: java_vm_ext.cc:542]   native: #06 pc 000d4a5e  /system/lib/libart.so (art::(anonymous namespace)::ScopedCheck::CheckPossibleHeapValue(art::ScopedObjectAccess&, char, art::(anonymous namespace)::JniValueType)+1230)
    F m.company.mr: java_vm_ext.cc:542]   native: #07 pc 000d3bdb  /system/lib/libart.so (art::(anonymous namespace)::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::(anonymous namespace)::JniValueType*)+811)
    F m.company.mr: java_vm_ext.cc:542]   native: #08 pc 000d828a  /system/lib/libart.so (art::(anonymous namespace)::CheckJNI::GetMethodIDInternal(char const*, _JNIEnv*, _jclass*, char const*, char const*, bool)+922)
    F m.company.mr: java_vm_ext.cc:542]   native: #09 pc 000c607e  /system/lib/libart.so (art::(anonymous namespace)::CheckJNI::GetStaticMethodID(_JNIEnv*, _jclass*, char const*, char const*)+46)
    F m.company.mr: java_vm_ext.cc:542]   native: #10 pc 002d5527  /data/app/com.company.mri-wprr13801Hc9xLloo20Lxg==/lib/x86/libQt5Core.so (void QJNIObjectPrivate::callStaticMethod<void>(_jclass*, char const*, char const*, ...)+87)
    F m.company.mr: java_vm_ext.cc:542]   native: #11 pc 000239f0  /data/data/com.company.mri/qt-reserved-files/plugins/platforms/android/libqtforandroid.so (???)
    F m.company.mr: java_vm_ext.cc:542]   at org.qtproject.qt5.android.QtNative.startQtApplication(Native method)
    F m.company.mr: java_vm_ext.cc:542]   at org.qtproject.qt5.android.QtNative$7.run(QtNative.java:387)
    F m.company.mr: java_vm_ext.cc:542]   at org.qtproject.qt5.android.QtThread$1.run(QtThread.java:61)
    F m.company.mr: java_vm_ext.cc:542]   at java.lang.Thread.run(Thread.java:764)
    F m.company.mr: java_vm_ext.cc:542]
    

    I have no idea what is the problem in here. I am not familiar with Java at all. Also the notification example doesnt really explain how is everything connected in here.
    What could be causing this null ptr exception?


  • Qt Champions 2018

    @Bremenpl said in Calling Java method from within Qt yields exception:

    F m.company.mr: java_vm_ext.cc:542] JNI DETECTED ERROR IN APPLICATION: JNI GetStaticMethodID called with pending exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object com.company.mri.NotificationClient.getSystemService(java.lang.String)' on a null object reference

    Your m_instance seems to be null: did you create an instance of NotificationClient at some point as you're initialising m_instance in its constructor? You could create an instance in notify(...).



  • @jsulm hi, thanks for answer. I am not familiar with java syntax at all. This example is nearly a copy paste from the qt example where it worked. This is what makes me think that there might be a problem somewhere around the java class within cpp code.


  • Qt Champions 2018

    @Bremenpl It doesn't look like an issue in C++ code - you simply do not have an instance of that Java class. That's all. Take a closer look at the Java code: the instance is assigned to m_instance inside NotificationClient constructor, but since the NotificationClient instance is never created the constructor is not called and m_instance is invalid. Add this line

    m_instance = NotificationClient();
    

    to showNotification (at the beginning) and see what happens.



  • @jsulm i will check that, but could you elaborate why does the example code work?


  • Qt Champions 2018

    @Bremenpl said in Calling Java method from within Qt yields exception:

    but could you elaborate why does the example code work?

    Take a look at this (from the example):

    A NotificationClient object is exposed to the QML in the main source file, main.cpp:
    
    QQuickView view;
    
    NotificationClient *notificationClient = new NotificationClient(&view);
    view.engine()->rootContext()->setContextProperty(QLatin1String("notificationClient"),
                                                         notificationClient);
    

    As you can see in the example an instance of NotificationClient is created, so m_instance is set. I guess you don't have this part of the code in your project?



  • @jsulm no, i dont... Thank you very much. Will check this asap.



  • @jsulm But here is the thing: In some weird way that is not fully understandable to me, this java class is connected with QML, that in my opinion should have nothing to do with anything related to this topic... It seems like somehow the cpp class name NotificationClient being the same as the java class name is not an accident? Is there a way to disengage all those hard coded components from this example?


  • Qt Champions 2018

    @Bremenpl Yes, you're right the code I pasted is C++. I'm not an JNI expert, so I don't know where the instance is created. All I know is what the error message says: there is no instance.
    "F m.company.mr: java_vm_ext.cc:542] JNI DETECTED ERROR IN APPLICATION: JNI GetStaticMethodID called with pending exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object com.company.mri.NotificationClient.getSystemService(java.lang.String)' on a null object reference"

    Maybe somebody else has an idea what is missing in your project.

    Does the example application work?



  • @jsulm Yes, the example works perfectly well. But my problem is that I am unable to figure out what is necessary in that example and what is not, since it is not described. For instance, I dont need to export any methods to the QML side. I also have no clue either the cpp NotificationClient class has the same name as java class for a reason, or it is a coincidence. At last, after you have suggested me what is wrong, I dont know how to create the java class instance via cpp without doing any unnecessarily operations on QML (or furthermore, creating an additional cpp class just for this end).



  • So I am just bumping the topic since it feels like I am close (thanks @jsulm). I would really appreciate anyone explaining me the magic happening in that android notofication example (about the namimg and everything)...


Log in to reply