调用实例方法时为何使用QTimer?JNI场景技术疑问
问题:JNI中调用setRotation为何使用QTimer?
我希望在Java本地方法(JNI)中运行setRotation函数,找到了如下解决方案。我理解该方案是为了让setRotation在与C++类相同的线程中执行,但不清楚为何要使用QTimer?
ImageOrientation::ImageOrientation(QObject *parent) : QObject{parent} { QJniObject javaClass = QNativeInterface::QAndroidApplication::context(); javaClass.callMethod<void>("setPointer","(J)V",(long long)(ImageOrientation*)this); setRotation(0); } extern "C" { JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_setNativeRotation (JNIEnv *, jobject, jint rotation, jlong ptr){ QPointer<ImageOrientation> orientation = reinterpret_cast<ImageOrientation*>(ptr); auto setupTimer = [](QPointer<ImageOrientation> orientation,int rotation){ QTimer *t = new QTimer(nullptr); t->setSingleShot(true); QObject::connect(t, &QTimer::timeout, [t, orientation, rotation](){ if(!orientation.isNull()){ orientation->setRotation(rotation); t->deleteLater(); } }); t->start(0); }; QMetaObject::invokeMethod(orientation->thread(), [setupTimer, orientation, rotation]() { setupTimer(orientation, rotation); }); qDebug() << rotation; } } int ImageOrientation::rotation() const { return m_rotation; } void ImageOrientation::setRotation(int newRotation) { if (m_rotation == newRotation) return; m_rotation = newRotation; emit rotationChanged(newRotation); }
补充说明:QTimer并非必需。
解答
原代码中QTimer的作用
这里用QTimer::start(0)是把setRotation的调用延迟到目标线程事件循环的下一个周期执行,本质是借QTimer的超时事件,把任务放到事件队列的末尾。这么做可能是原作者担心直接在invokeMethod的lambda里调用setRotation会和当前线程的其他事件处理冲突,或者想确保函数在事件循环空闲时执行。
为什么QTimer完全多余
QMetaObject::invokeMethod本身就支持将任务投递到目标线程的事件队列(默认用Qt::AutoConnection:如果目标线程是当前线程就直接调用,否则投递到事件队列),完全不需要QTimer中转。
优化后的代码
直接去掉QTimer,在invokeMethod的lambda里调用setRotation即可,效果完全一致且更简洁:
extern "C" { JNIEXPORT void JNICALL Java_com_example_myapplication_MainActivity_setNativeRotation (JNIEnv *, jobject, jint rotation, jlong ptr){ QPointer<ImageOrientation> orientation = reinterpret_cast<ImageOrientation*>(ptr); QMetaObject::invokeMethod(orientation->thread(), [orientation, rotation]() { if(!orientation.isNull()){ orientation->setRotation(rotation); } }); qDebug() << rotation; } }
这样直接通过invokeMethod把任务投递到目标线程的事件队列,省去了额外的QTimer对象创建和销毁的开销。
内容的提问来源于stack exchange,提问作者sash
相关产品推荐
相关产品推荐

