summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qjnihelpers.cpp
diff options
context:
space:
mode:
authorBogDan Vatra <bogdan@kdab.com>2016-01-15 17:08:19 +0200
committerBogDan Vatra <bogdan@kdab.com>2016-01-15 16:13:29 +0000
commite666ce162b75e926d8746177a30e38d124767e3d (patch)
tree5ef9e994e4033b24d034a3142437ab9b31a3fd85 /src/corelib/kernel/qjnihelpers.cpp
parent1a88b2f768e86474f8fc6facf60cd0dd46a555c8 (diff)
Helper function needed to run Runnables on Android UI thread easily.
Add a function to allow the users to easily run asynchronously Runnables for any thread directly on Andoroid UI thread. Change-Id: I631bf8a2c602e038039fec621ec01272af20a400 Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
Diffstat (limited to 'src/corelib/kernel/qjnihelpers.cpp')
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp55
1 files changed, 38 insertions, 17 deletions
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index 6aba5b1e51..f5e4aceff3 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -40,9 +40,12 @@
#include "qjnihelpers_p.h"
#include "qmutex.h"
#include "qlist.h"
+#include "qsemaphore.h"
#include "qvector.h"
#include <QtCore/qrunnable.h>
+#include <deque>
+
QT_BEGIN_NAMESPACE
static JavaVM *g_javaVM = Q_NULLPTR;
@@ -50,17 +53,24 @@ static jobject g_jActivity = Q_NULLPTR;
static jobject g_jClassLoader = Q_NULLPTR;
static jint g_androidSdkVersion = 0;
static jclass g_jNativeClass = Q_NULLPTR;
-static jmethodID g_runQtOnUiThreadMethodID = Q_NULLPTR;
+static jmethodID g_runPendingCppRunnablesMethodID = Q_NULLPTR;
+Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables);
+Q_GLOBAL_STATIC(QMutex, g_pendingRunnablesMutex);
-static void onAndroidUiThread(JNIEnv *, jclass, jlong thiz)
+// function called from Java from Android UI thread
+static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/)
{
- QRunnable *runnable = reinterpret_cast<QRunnable *>(thiz);
- if (runnable == 0)
- return;
-
- runnable->run();
- if (runnable->autoDelete())
- delete runnable;
+ for (;;) { // run all posted runnables
+ g_pendingRunnablesMutex->lock();
+ if (g_pendingRunnables->empty()) {
+ g_pendingRunnablesMutex->unlock();
+ break;
+ }
+ QtAndroidPrivate::Runnable runnable(std::move(g_pendingRunnables->front()));
+ g_pendingRunnables->pop_front();
+ g_pendingRunnablesMutex->unlock();
+ runnable(); // run it outside the sync block!
+ }
}
namespace {
@@ -268,7 +278,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
g_javaVM = vm;
static const JNINativeMethod methods[] = {
- {"onAndroidUiThread", "(J)V", reinterpret_cast<void *>(onAndroidUiThread)},
+ {"runPendingCppRunnables", "()V", reinterpret_cast<void *>(runPendingCppRunnables)},
{"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
{"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
};
@@ -278,9 +288,9 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
if (!regOk && exceptionCheck(env))
return JNI_ERR;
- g_runQtOnUiThreadMethodID = env->GetStaticMethodID(jQtNative,
- "runQtOnUiThread",
- "(J)V");
+ g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative,
+ "runPendingCppRunnablesOnUiThread",
+ "()V");
g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative));
env->DeleteLocalRef(jQtNative);
@@ -311,10 +321,21 @@ jint QtAndroidPrivate::androidSdkVersion()
void QtAndroidPrivate::runOnUiThread(QRunnable *runnable, JNIEnv *env)
{
- Q_ASSERT(runnable != 0);
- env->CallStaticVoidMethod(g_jNativeClass, g_runQtOnUiThreadMethodID, reinterpret_cast<jlong>(runnable));
- if (exceptionCheck(env) && runnable != 0 && runnable->autoDelete())
- delete runnable;
+ runOnAndroidThread([runnable]() {
+ runnable->run();
+ if (runnable->autoDelete())
+ delete runnable;
+ }, env);
+}
+
+void QtAndroidPrivate::runOnAndroidThread(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env)
+{
+ g_pendingRunnablesMutex->lock();
+ const bool triggerRun = g_pendingRunnables->empty();
+ g_pendingRunnables->push_back(runnable);
+ g_pendingRunnablesMutex->unlock();
+ if (triggerRun)
+ env->CallStaticVoidMethod(g_jNativeClass, g_runPendingCppRunnablesMethodID);
}
void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)