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>());
-
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.