You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用实例方法时为何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 19:02:03