I'd like to start a new series of Qt on Android articles, these will be small articles which will focus on useful features that you'll need on Android but which don't have any Qt API (yet).
I'll start with two pretty useful functions. These functions will help us to run C++ code directly on Android UI thread without writing any Java code. Qt 5.7 will bring will bring the same functionality.
Until Qt 5.7 is out, we need to use our own implementation, let's check the code:
androidutils.h
I think the comments are more than enough to understand the code. Let's check the implementation:
androidutils.cpp
Let's take a closer look at the source code:
- runOnAndroidThread enqueues the runnable in s_pendingRunnables deque, and if it's the only runnable in deque, it calls Activity.runOnUiThread with our custom Runnable (it's source code is listed below). This runnable is picked up by Android UI event loop and is executed on Android UI thread. Our custom Runnable just calls runPendingCppRunnables native function. For more information Qt on Android thread, you need to check How to access and use Android Java API from your Qt on Android using JNI in a safe way article.
- runOnAndroidThreadSync uses a semaphore to wait until the runnable is executed then exists.
- Java_com_kdab_android_utils_Runnable_runPendingCppRunnables runs all pending C++ runnables on Android UI thread.
And finally, let's check our custom Runnable:
Runnable.java
The implementation is very easy, the run function just calls runPendingCppRunnables native method which we'll run all C++ runnables on Android UI thread.
How to use these functions? Well, it's pretty easy:
First step is to add KDAB's Android utils to your project.
- clone KDAB's Android repository ( $ git clone https://github.com/KDAB/android.git )
- copy the contents of utils folder to your project (androidutils.cpp, androidutils.h and android folder)
- add them to your project
QT += androidextras
SOURCES += androidutils.cpp
HEADERS += androidutils.h
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
Let's create a Qt Button class (which just wraps an Android Button Java object).
We need to use runOnAndroidThreadSync to make sure m_button is initialized properly in our C++ constructor.
Let's check QAndroidJniObject parameters:
Let's set a property
We don't need to wait until the property is set, therefore we can use runOnAndroidThread in this case. Because runOnAndroidThread is asynchronous, we must copy all the captured values! Otherwise they will be invalid when the runnable is executed on Android UI thread.
Let's take a look to callMethod parameters:
Let's get a property
Because runOnAndroidThreadSync waits, we can capture res variable by reference, this way we can safely set the value on Android UI thread and return it on Qt thread.
Let's check callObjectMethod parameters:
- "getText" - is the method name
- "()Ljava/lang/CharSequence;" - is the method signature
.toString() converts a java string to a QString.
You can download the source code from here : https://github.com/KDAB/android
2 Comments
7 - Apr - 2017
Jason
Now that 5.7 is out, how do we do this?
10 - Oct - 2019
Jan
After Qt 5.7: https://doc.qt.io/qt-5/qtandroid.html#runOnAndroidThread looks like it does what above code does.