From e666ce162b75e926d8746177a30e38d124767e3d Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 15 Jan 2016 17:08:19 +0200 Subject: 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 --- src/corelib/kernel/qjnihelpers.cpp | 55 ++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 17 deletions(-) (limited to 'src/corelib/kernel/qjnihelpers.cpp') 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 +#include + 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, 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(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(onAndroidUiThread)}, + {"runPendingCppRunnables", "()V", reinterpret_cast(runPendingCppRunnables)}, {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast(dispatchGenericMotionEvent)}, {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast(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(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(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) -- cgit v1.2.3