diff --git a/src/corelib/platform/android/qandroiditemmodelproxy.cpp b/src/corelib/platform/android/qandroiditemmodelproxy.cpp index eebd5582bd9..72f79b9f717 100644 --- a/src/corelib/platform/android/qandroiditemmodelproxy.cpp +++ b/src/corelib/platform/android/qandroiditemmodelproxy.cpp @@ -11,9 +11,13 @@ QT_BEGIN_NAMESPACE using namespace QtJniTypes; +std::map QAndroidItemModelProxy::s_mutexes = + std::map{}; + jint QAndroidItemModelProxy::columnCount(const QModelIndex &parent) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto parentIndex = QAndroidModelIndexProxy::jInstance(parent); return jInstance.callMethod("columnCount", parentIndex); } @@ -21,6 +25,7 @@ jint QAndroidItemModelProxy::columnCount(const QModelIndex &parent) const bool QAndroidItemModelProxy::canFetchMore(const QModelIndex &parent) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto parentIndex = QAndroidModelIndexProxy::jInstance(parent); return jInstance.callMethod("canFetchMore", parentIndex); } @@ -33,6 +38,7 @@ bool QAndroidItemModelProxy::canFetchMoreDefault(const QModelIndex &parent) cons QVariant QAndroidItemModelProxy::data(const QModelIndex &index, int role) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto jIndex = QAndroidModelIndexProxy::jInstance(index); QJniObject jData = jInstance.callMethod("data", jIndex, role); return QAndroidTypeConverter::toQVariant(jData); @@ -41,6 +47,7 @@ QVariant QAndroidItemModelProxy::data(const QModelIndex &index, int role) const QModelIndex QAndroidItemModelProxy::index(int row, int column, const QModelIndex &parent) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); JQtModelIndex jIndex = jInstance.callMethod( "index", row, column, QAndroidModelIndexProxy::jInstance(parent)); return QAndroidModelIndexProxy::qInstance(jIndex); @@ -49,6 +56,7 @@ QModelIndex QAndroidItemModelProxy::index(int row, int column, const QModelIndex QModelIndex QAndroidItemModelProxy::parent(const QModelIndex &index) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto jIndex = QAndroidModelIndexProxy::jInstance(index); return QAndroidModelIndexProxy::qInstance( @@ -57,6 +65,7 @@ QModelIndex QAndroidItemModelProxy::parent(const QModelIndex &index) const int QAndroidItemModelProxy::rowCount(const QModelIndex &parent) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto parentIndex = QAndroidModelIndexProxy::jInstance(parent); return jInstance.callMethod("rowCount", parentIndex); @@ -65,6 +74,7 @@ int QAndroidItemModelProxy::rowCount(const QModelIndex &parent) const QHash QAndroidItemModelProxy::roleNames() const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); QHash roleNames; HashMap hashMap = jInstance.callMethod("roleNames"); @@ -88,6 +98,7 @@ QHash QAndroidItemModelProxy::defaultRoleNames() const void QAndroidItemModelProxy::fetchMore(const QModelIndex &parent) { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto parentIndex = QAndroidModelIndexProxy::jInstance(parent); jInstance.callMethod("fetchMore", parentIndex); } @@ -100,6 +111,7 @@ void QAndroidItemModelProxy::fetchMoreDefault(const QModelIndex &parent) bool QAndroidItemModelProxy::hasChildren(const QModelIndex &parent) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto parentIndex = QAndroidModelIndexProxy::jInstance(parent); return jInstance.callMethod("hasChildren", parentIndex); } @@ -112,6 +124,7 @@ bool QAndroidItemModelProxy::hasChildrenDefault(const QModelIndex &parent) const QModelIndex QAndroidItemModelProxy::sibling(int row, int column, const QModelIndex &parent) const { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); return QAndroidModelIndexProxy::qInstance(jInstance.callMethod( "sibling", row, column, QAndroidModelIndexProxy::jInstance(parent))); } @@ -124,6 +137,7 @@ QModelIndex QAndroidItemModelProxy::siblingDefault(int row, int column, const QM bool QAndroidItemModelProxy::setData(const QModelIndex &index, const QVariant &value, int role) { Q_ASSERT(jInstance.isValid()); + const QMutexLocker lock = getMutexLocker(this); auto jIndex = QAndroidModelIndexProxy::jInstance(index); auto jValue = QAndroidTypeConverter::toJavaObject(value, QJniEnvironment::getJniEnv()); return jInstance.callMethod("setData", jIndex, jValue, role); @@ -157,8 +171,10 @@ QAndroidItemModelProxy::createNativeProxy(QJniObject itemModel) itemModel.callMethod("setNativeReference", reinterpret_cast(nativeProxy)); connect(nativeProxy, &QAndroidItemModelProxy::destroyed, nativeProxy, [](QObject *obj) { auto proxy = qobject_cast(obj); - if (proxy) + if (proxy) { + const QMutexLocker lock = getMutexLocker(proxy); proxy->jInstance.callMethod("detachFromNative"); + } }); connect(nativeProxy, &QAndroidItemModelProxy::dataChanged, nativeProxy, @@ -167,6 +183,7 @@ QAndroidItemModelProxy::createNativeProxy(QJniObject itemModel) auto proxy = qobject_cast(nativeProxy); if (proxy) { QJniObject jInstance = proxy->jInstance; + const QMutexLocker lock = getMutexLocker(proxy); jInstance.callMethod("handleDataChanged", QAndroidModelIndexProxy::jInstance(topLeft), QAndroidModelIndexProxy::jInstance(bottomRight), diff --git a/src/corelib/platform/android/qandroiditemmodelproxy_p.h b/src/corelib/platform/android/qandroiditemmodelproxy_p.h index 350fc643ca1..fdcbed86f02 100644 --- a/src/corelib/platform/android/qandroiditemmodelproxy_p.h +++ b/src/corelib/platform/android/qandroiditemmodelproxy_p.h @@ -22,6 +22,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -67,7 +68,8 @@ public: Q_ASSERT(jvmObject); auto model = qobject_cast(nativeInstance(jvmObject)); Q_ASSERT(model); - return safeCall(model, std::forward(func), std::forward(args)...); + const QMutexLocker lock = getMutexLocker(model); + return std::invoke(std::forward(func), model, std::forward(args)...); } template @@ -76,7 +78,8 @@ public: Q_ASSERT(jvmObject); auto model = nativeInstance(jvmObject); Q_ASSERT(model); - return safeCall(model, std::forward(func), std::forward(args)...); + const QMutexLocker lock = getMutexLocker(model); + return std::invoke(std::forward(func), model, std::forward(args)...); } template @@ -86,33 +89,13 @@ public: Q_ASSERT(jvmObject); auto nativeModel = nativeInstance(jvmObject); auto nativeProxyModel = qobject_cast(nativeModel); + const QMutexLocker lock = getMutexLocker(nativeModel); if (nativeProxyModel) - return safeCall(nativeProxyModel, std::forward(defaultFunc), - std::forward(args)...); + return std::invoke(std::forward(defaultFunc), nativeProxyModel, + std::forward(args)...); else - return safeCall(nativeModel, std::forward(func), std::forward(args)...); - } - template - static auto safeCall(Object *object, Func &&func, Args &&...args) - { - using ReturnType = decltype(std::invoke(std::forward(func), object, - std::forward(args)...)); - - if constexpr (std::is_void_v) { - QMetaObject::invokeMethod(object, std::forward(func), Qt::AutoConnection, - std::forward(args)...); - } else { - ReturnType returnValue; - - const auto connectionType = object->thread() == QThread::currentThread() - ? Qt::DirectConnection - : Qt::BlockingQueuedConnection; - - QMetaObject::invokeMethod(object, std::forward(func), connectionType, - qReturnArg(returnValue), std::forward(args)...); - return returnValue; - } + return std::invoke(std::forward(func), nativeModel, std::forward(args)...); } static jint jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent); @@ -216,6 +199,19 @@ public: static bool registerProxyNatives(QJniEnvironment &env); private: + static std::map s_mutexes; + + Q_REQUIRED_RESULT static QMutexLocker + getMutexLocker(const QAbstractItemModel *model) + { + auto [iter, inserted] = s_mutexes.try_emplace(model); + if (inserted) + QObject::connect(model, &QAbstractItemModel::destroyed, model, [](QObject *model) { + s_mutexes.erase(reinterpret_cast(model)); + }); + return QMutexLocker(&iter->second); + } + QJniObject jInstance; friend class QAndroidModelIndexProxy; };