summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java22
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp55
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h4
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 <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);