diff options
author | BogDan Vatra <bogdan@kdab.com> | 2016-01-15 17:08:19 +0200 |
---|---|---|
committer | BogDan Vatra <bogdan@kdab.com> | 2016-01-15 16:13:29 +0000 |
commit | e666ce162b75e926d8746177a30e38d124767e3d (patch) | |
tree | 5ef9e994e4033b24d034a3142437ab9b31a3fd85 /src/corelib/kernel | |
parent | 1a88b2f768e86474f8fc6facf60cd0dd46a555c8 (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')
-rw-r--r-- | src/corelib/kernel/qjnihelpers.cpp | 55 | ||||
-rw-r--r-- | src/corelib/kernel/qjnihelpers_p.h | 4 |
2 files changed, 42 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) diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index 5ecab16c85..3f24597312 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -53,6 +53,7 @@ #include <jni.h> #include <QtCore/qglobal.h> +#include <functional> QT_BEGIN_NAMESPACE @@ -96,11 +97,14 @@ namespace QtAndroidPrivate virtual bool handleKeyEvent(jobject event) = 0; }; + typedef std::function<void()> Runnable; + Q_CORE_EXPORT jobject activity(); Q_CORE_EXPORT JavaVM *javaVM(); Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env); jobject classLoader(); Q_CORE_EXPORT jint androidSdkVersion(); + Q_CORE_EXPORT void runOnAndroidThread(const Runnable &runnable, JNIEnv *env); Q_CORE_EXPORT void runOnUiThread(QRunnable *runnable, JNIEnv *env); Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data); |