Qt Android: How to call Toast.makeText from Java?



  • Hi; I want to call Toast.makeText method from Java in Qt / C++. Codes:
    I added QT += androidextras in .pro file.

    Toast.java:

    package com.classes.java;
    
    public class Toast {
      public static void makeText(String text, int duration) {
        Toast.makeText(getApplicationContext(), text, duration).show();
      }
    }
    

    toast.h:

    #ifndef TOAST_H
    #define TOAST_H
    
    #include <QObject>
    #include <QAndroidJniObject>
    
    class Toast : public QObject
    {
      Q_OBJECT
    public:
      explicit Toast(QObject* parent = 0);
      Q_INVOKABLE void make_text(QString& text, int duration);
    
    signals:
    
    public slots:
    };
    
    #endif // TOAST_H
    
    

    toast.cpp:

    #include "toast.h"
    
    Toast::Toast(QObject* parent) : QObject(parent)
    {
    }
    
    void Toast::make_text(QString& text, int duration)
    {
      QAndroidJniObject txt = QAndroidJniObject::fromString(text);
      QAndroidJniObject::callStaticObjectMethod(
          "com/classes/java/Toast",
          "makeText",
          "(Ljava/lang/String;I)V",
          txt.object<jstring>(), duration);
    }
    

    main.cpp:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QtQml>
    
    #include "toast.h"
    
    int main(int argc, char* argv[])
    {
      QGuiApplication app(argc, argv);
    
      QQmlApplicationEngine engine;
      qmlRegisterType<Toast>("java.class", 1, 0, "Toast");
      engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
      return app.exec();
    }
    

    main.qml:

    import QtQuick 2.6
    import QtQuick.Window 2.2
    import Qt.labs.controls 1.0
    import java.class 1.0;
    
    Window {
      visible: true
    
      Toast {
        id: toast
      }
    
      Button {
        id: button
        text: "Click Me!"
        onClicked: toast.make_text("Hello World!", 2000)
      }
    }
    

    I get this error message:

    UserPath\build-QtMobileTest-Android_for_armeabi_v7a_GCC_4_9_Qt_5_6_0-Release\android-build\src\com\classes\java\Toast.java:9: error: cannot find symbol
        Toast.makeText(getApplicationContext(), text, duration).show();
                       ^
      symbol:   method getApplicationContext()
      location: class Toast
    Note: UserPath\build-QtMobileTest-Android_for_armeabi_v7a_GCC_4_9_Qt_5_6_0-Release\android-build\__qt5__android__files__\src\org\qtproject\qt5\android\bindings\QtActivity.java uses or overrides a deprecated API.
    Note: Recompile with -Xlint:deprecation for details.
    1 error
    :compileDebugJava FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':compileDebugJava'.
    > Compilation failed; see the compiler error output for details.
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    BUILD FAILED
    

    I think I need android context for getApplicationContext() but I do not know how can I get context? How can I call Toast.makeText method using Qt / C++ JNI? Thanks.



  • You need to create a static instance of your main java class object and call the method that way. So in your 'JavaMain':

    public class MyJavaMain extends QtActivity {
    
        // Singleton Instance
        public  static MyJavaMain mInstance;
    
        ...
    
        public MyJavaMain () {
            Log.d(QtApplication.QtTAG, "Java constructor called.");
            mInstance = this;
        }
    
        ...
    
        public static MyMethodCallToast(final String message) {
             mInstance.runOnUiThread(new Runnable() {
                public void run() {
                   Toast.makeText(mInstance.getApplicationContext(),
                                  message,
                                  Toast.LENGTH_SHORT).show();
               }
            });
        }  
    }
    

    Hopefully that helps. Cheers!



  • @Carmoneer Thanks, I get this error:

    W/dalvikvm( 7847): Exception thrown (Ljava/lang/NullPointerException;) while throwing internal exception (Ljava/lang/NullPointerException;)
    W/InputMethodManagerService(  589): Starting input on non-focused client com.android.internal.view.IInputMethodClient$Stub$Proxy@429dfe58 (uid=10170 pid=7847)
    

    NullPointerException error?



  • I think it may be an issue with the signature call on the .cpp side, specifically "(Ljava/lang/String;I)V". Try:

    QString toastMessage = "My message";
    QAndroidJniObject javaMessage = QAndroidJniObject::fromString(toastMessage);
    QAndroidJniObject::callStaticMethod<void>("com/app/myApp/MyJavaMain",
                                              "MyMethodCallToast",
                                              "(Ljava/lang/String;)V",
                                              javaMessage.object<jstring>());
    


  • @Carmoneer Thanks, but I get same error again. This NullPointerException is text.



  • I tried:

    // ToastMessage.java file
    ...
    public static void makeText(final String text) {
        mInstance.runOnUiThread(new Runnable() {
          public void run() {
            Toast.makeText(mInstance.getApplicationContext(), "text", Toast.LENGTH_LONG).show();
          }
        });
      }
    ...
    

    This code give error. I put the string ("text") but I get still NullPointerException error.



  • The only other thing I can think of is maybe because you have a separate 'Toast' class, it's calling that nullpointerexception. I don't have a separate class for my Toast calls.

    Maybe

    Toast.makeText(Classname.class, message, Toast.LENGTH_SHORT).show();
    

    is what you need to do?

    I simply import android.widget.Toast and make my Toast calls.



  • @Carmoneer My ToastMessage.java file:

    package com.classes.java;
    
    import org.qtproject.qt5.android.bindings.QtActivity;
    import android.widget.Toast;
    
    public class ToastMessage extends QtActivity {
      public static ToastMessage mInstance;
    
      public ToastMessage() {
        mInstance = this;
      }
    
      public static String msg() {
        return "<HELLO WORLD!>";
      }
    
      public static void makeText(final String text) {
        mInstance.runOnUiThread(new Runnable() {
          public void run() {
            Toast.makeText(mInstance.getApplicationContext(), "text", Toast.LENGTH_LONG).show();
          }
        });
      }
    }
    

    I want to learn how to call java codes from C++. Have you an example project for the android toast message?



  • This is how I extend the framework for QtActivity:

    package com.app.myapp;
    
    import org.qtproject.qt5.android.bindings.QtApplication;
    import org.qtproject.qt5.android.bindings.QtActivity;
    
    
    import android.widget.Toast;
    
    
    /** --------------------------------------------------------------------------
    ** @MyJavaNatives
    ** Static methods called from .cpp side. Sends data to .cpp
    ** -------------------------------------------------------------------------*/
    class MyJavaNatives
    {
        public static native void showToast(final String message);
    }
    
    /** --------------------------------------------------------------------------
    ** @JavaMain (Only one class can extend QtActivity)
    ** -------------------------------------------------------------------------*/
    public class JavaMain extends QtActivity {
        // Singleton Instance
        public  static JavaMain mInstance;
    
        public JavaMain() {
            Log.d(QtApplication.QtTAG, "Java constructor called.");
            mInstance = this;
        }
    
        // Called at the start of the full lifetime.
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(QtApplication.QtTAG, "onCreate Called");
        }
    
    
        // Called at the start of the visible lifetime.
        @Override
        protected void onStart() {
            super.onStart();
        }
    
        // Called at the start of the active lifetime.
        @Override
        public synchronized void onResume() {
            super.onResume();
        }
    
        // Called at the end of the active lifetime.
        @Override
        protected synchronized void onPause() {
            super.onPause();
        }
    
        // Called at the end of the full lifetime.
        @Override
        protected void onDestroy() {
            // Clean up any resources including ending threads,
            // closing database connections etc.
            super.onDestroy();
        }
    
        // Called at the end of the visible lifetime.
        @Override
        protected void onStop() {
            // Suspend remaining UI updates, threads, or processing
            // that aren’t required when the Activity isn’t visible.
            // Persist all edits or state changes
            // as after this call the process is likely to be killed.
            super.onStop();
     
        }
    
        // Called before subsequent visible lifetimes
        // for an activity process.
        @Override
        protected void onRestart() {
            // Load changes knowing that the activity has already
            // been visible within this process.
            super.onRestart();
        }
    
    
        /** ------------------------------------------------------------------------
        ** @Toast
        ** Show toast messge.
        ** -----------------------------------------------------------------------*/
        public static void showToast(final String message) {
            mInstance.runOnUiThread(new Runnable() {
               public void run() {
                   Toast.makeText(mInstance.getApplicationContext(),
                                  message,
                                  Toast.LENGTH_SHORT).show();
               }
            });
        }
    }
    

    and then on the .cpp to call the message:

                QAndroidJniObject::callStaticMethod<void>("com/app/myapp/JavaMain",
                                                          "showToast",
                                                          "(Ljava/lang/String;)V",
                                                          QAndroidJniObject::fromString("This is my toast message!").object<jstring>());
    

    That is the basics to setting up a 'Main' java class that extends QtActivity. Hopefully that should at least steer you in the right direction. Good luck :)



  • @Carmoneer Ohh thanks. I tried this project, but it give same error:

    W/dalvikvm(18212): Exception thrown (Ljava/lang/NullPointerException;) while throwing internal exception (Ljava/lang/NullPointerException;)
    I/InputDispatcher(  589): Delivering touch to (18212): action: 0x0, toolType: 1
    I/InputDispatcher(  589): Delivering touch to (18212): action: 0x1, toolType: 1
    

    I am sharing this project source codes: Project Source Codes.



  • There is an android-extra example called 'notification' in Qt SDK examples. Just change the notify function in NotificationClient.java to display the toast. Maybe it will work.



  • @douyw thanks, I tried this method and it is work. Interesting! I do not understand. What is the problem? How can I learn it?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.