Solved Qt Android Problem
-
Hi;
I am working Qt for Android. But I don't understand somethings. Qt doc means about QAndroidJniObject QtAndroid::androidActivity() member function: Returns a handle to this applications main Activity. But which is activity? Which is main activity? My application created with QML and QML windows are not Activity, activities defined on Android (Java) only. I want to define toast message function:package com.xxx.android; import android.content.Context; import android.widget.Toast; import org.qtproject.qt5.android.bindings.QtActivity; public class MyActivity extends QtActivity { public void makeText(Context context, CharSequence text, int duration) { Toast.makeText(context, text, duration).show(); } }
And I want to call this method in Qt:
... void TestClass::toast_message(/*I don't know Context class in Qt*/const QString& text, int duration) { QAndroidJniObject mytext = QAndroidJniObject::fromString(text); QAndroidJniObject::callObjectMethod("com/xxx/android/MyActivity", "makeText", "(Ljava/lang/String;I)V", mytext.object<jstring>(), duration); } ...
But my text type is CharSequence, not String. But defined jstring in Qt. Then I want to put parameter this member function as Context context but I could not do it. How can I understand struction of Qt for Android? I know Java for Android.
-
You can pass
String
instead ofCharSequence
sinceString
isCharSequence
. As for the context, the activity is aContext
subclass.Java:
public void makeText(String text, int duration) { Toast.makeText(this, text, duration).show(); }
C++:
void TestClass::toast_message(const QString& text, int duration) { QAndroidJniObject mytext = QAndroidJniObject::fromString(text); QAndroidJniObject::callObjectMethod("com/xxx/android/MyActivity", "makeText", "(Ljava/lang/String;I)V", mytext.object<jstring>(), duration); }
-
@Violet-Giraffe Thanks but that code doesn't run. Did you try?
I wrote this code (I look KDAB webpage):// testclass.h class TestClass : public QObject { Q_OBJECT public: enum Duration { SHORT = 0, LONG = 1 }; explicit TestClass(QObject *parent = 0); Q_INVOKABLE void toast_message(const QString& text, Duration duration); signals: public slots: };
// testclass.cpp #include "testclass.h" TestClass::TestClass(QObject *parent) : QObject(parent) { } void TestClass::toast_message(const QString& text, Duration duration = SHORT) { QAndroidJniObject _text = QAndroidJniObject::fromString(text); QAndroidJniObject toast = QAndroidJniObject::callStaticObjectMethod("android/widget/Toast", "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;", QtAndroid::androidActivity().object(), _text.object(), jint(duration)); toast.callMethod<void>("show"); }
I put this code in main.cpp:
qmlRegisterType<TestClass>("com.xxx.TestClass", 1, 0, "TestClass");
// .qml file: import QtQuick 2.7 import QtQuick.Dialogs 1.2 import com.xxx.TestClass 1.0 Page1Form { TestClass { id: test_class } button1.onClicked: { test_class.toast_message("Hello World!") } }
I run this application and I click the button then I get this error message on the log window:
W/libQt_App.so(11956): qrc:/Page1.qml:17 ((null)): qrc:/Page1.qml:17: Error: Unknown method parameter type: Duration
What is the problem? -
@Ibrahim ,I think you need declare Q_ENUM(Duration) to register with Qt's meta object system, and using qRegisterMetaType
pls see link: http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#enumeration-types
and http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#enumeration-types-as-signal-and-method-parameters -
@kd_wala Thanks I added Q_ENUM(Duration) and I run the app. Then I get this message on the Android device: Unfortunately app has stopped.
Then I get this warning message on the log window:F/libc (27047): Fatal signal 11 (SIGSEGV) at 0x0000002c (code=1), thread 27218 (project.example)
I understand I need to use thread but how can I use thread for this member function (toast_message)?
Code:void TestClass::toast_message(const QString& text, Duration duration) { std::thread run([&] { QAndroidJniObject _text = QAndroidJniObject::fromString(text); QAndroidJniObject toast = QAndroidJniObject::callStaticObjectMethod( "android/widget/Toast", "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;", QtAndroid::androidActivity().object(), _text.object(), jint(duration)); toast.callMethod<void>("show"); }); run.join(); }
This code is not running.
-
I think it a problem when you call from Qt thread to Android thread,
on this link : http://www.kdab.com/qt-android-episode-7/
have a diagram about architecture between Android & Qt thread,
this link will help you solve problem, : https://www.kdab.com/qt-android-use-android-toast/
or if you have install Qt5.7, it already support some function for running on UI Android thread from c++. -
@kd_wala Thanks.
You said:if you have install Qt5.7, it already support some function for running on UI Android thread from c++.
What are some functions? I want to control all threads in Qt/C++, is this possible? I don't want running thread for Android in Java, can I do it in C++?
KDAB::Android::runOnAndroidThread()
member function is using thread from Java:void runOnAndroidThread(const Runnable &runnable) { s_pendingRunnablesMutex.lock(); bool triggerRun = s_pendingRunnables.empty(); s_pendingRunnables.push_back(runnable); s_pendingRunnablesMutex.unlock(); if (triggerRun) { QtAndroid::androidActivity().callMethod<void>("runOnUiThread", // This is Java Class. "(Ljava/lang/Runnable;)V", QAndroidJniObject("com/kdab/android/utils/Runnable").object()); } }
But I want to use all threads in C++ (std::thread, std::async, QThread etc.). Is this possible?
-
Hi @Ibrahim ,
in QtAndroidExtras, have include "qandroidfunctions.h", this file have some function that equal to KDAB::Android::runOnAndroidThread(),
You want to control all threads in Qt/C++, i think it ok, in c++ thread, you just call java via jni,
but if you want to access on UI of Android (in your case, show toast UI) you need run this code on main thread of Java,
One note is Qt event loop vs Android event loop run in different thread (https://www.kdab.com/qt-on-android-episode-1/) -
@kd_wala Thanks. I solved the problem:
void TestClass::toast_message(const QString& text, Duration duration) { QtAndroid::runOnAndroidThread([&] { QAndroidJniObject _text = QAndroidJniObject::fromString(text); QAndroidJniObject toast = QAndroidJniObject::callStaticObjectMethod( "android/widget/Toast", "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;", QtAndroid::androidActivity().object(), _text.object(), jint(duration)); toast.callMethod<void>("show"); }); }
This is running!