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/org/qtproject/qt5/android/QtNative.java | 22 +++++---- src/corelib/kernel/qjnihelpers.cpp | 55 +++++++++++++++------- src/corelib/kernel/qjnihelpers_p.h | 4 ++ 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index 5c9b203f4f..3729555d52 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -90,6 +90,12 @@ public class QtNative private static final int m_moveThreshold = 0; private static ClipboardManager m_clipboardManager = null; private static Method m_checkSelfPermissionMethod = null; + private static final Runnable runPendingCppRunnablesRunnable = new Runnable() { + @Override + public void run() { + runPendingCppRunnables(); + } + }; private static ClassLoader m_classLoader = null; public static ClassLoader classLoader() @@ -210,14 +216,14 @@ public class QtNative } } - private static void runQtOnUiThread(final long id) + private static void runPendingCppRunnablesOnUiThread() { - runAction(new Runnable() { - @Override - public void run() { - QtNative.onAndroidUiThread(id); - } - }); + synchronized (m_mainActivityMutex) { + if (!m_activityPaused && m_activity != null) + m_activity.runOnUiThread(runPendingCppRunnablesRunnable); + else + runAction(runPendingCppRunnablesRunnable); + } } public static boolean startApplication(String params, @@ -720,5 +726,5 @@ public class QtNative public static native void onActivityResult(int requestCode, int resultCode, Intent data); public static native void onNewIntent(Intent data); - public static native void onAndroidUiThread(long id); + public static native void runPendingCppRunnables(); } 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) 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 #include +#include QT_BEGIN_NAMESPACE @@ -96,11 +97,14 @@ namespace QtAndroidPrivate virtual bool handleKeyEvent(jobject event) = 0; }; + typedef std::function 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); -- cgit v1.2.3