Qt on Android 在一个Android服务中使用信号与槽

引言

上篇博文详细描述了如何在Qt项目中启动一个Android服务:
《Qt on Android 启动一个Android的服务(Service)》
本篇主要讲解如何在一个Android服务中使用Qt的信号与槽机制发射信号。主要使用了JNI和单例模式,使用单例模式可以在任何地方接收单例发射出的信号,因此创建一个单例模式,使用JNI让Android服务调用即可。

1.创建一个单例类

沿用上篇博文的代码,创建一个单例类并添加一个信号和发射该信号的函数。
singleton.h

#ifndef SINGLETON_H
#define SINGLETON_H

#include <QObject>

class Singleton : public QObject
{
    Q_OBJECT
public:
    static Singleton *getSingleton();
    void sendSignal();
signals:
    void mySignal();
private:
    Singleton(QObject *parent = 0);
    static Singleton *m_pThis;
};

#endif // SINGLETON_H

singleton.cpp

#include "singleton.h"
#include <QApplication>

Singleton *Singleton::m_pThis = NULL;
Singleton *Singleton::getSingleton()
{
    if(m_pThis == NULL) {
        m_pThis = new Singleton(qApp);
    }
    return m_pThis;
}

void Singleton::sendSignal()
{
    emit mySignal();
}
Singleton::Singleton(QObject *parent) : QObject(parent)
{

}

2.编写给Java调用的发射信号的JNI接口

创建一个C文件androidjni.h

#ifndef ANDROIDJNI
#define ANDROIDJNI

#include "singleton.h"
#include <jni.h>
#include <QDebug>
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>

static void sendSignal(JNIEnv *env, jobject thiz)
{
    qDebug("jni");
    Singleton *pSto = Singleton::getSingleton();
    pSto->sendSignal();
}


bool registerNativeMethods()
{
    JNINativeMethod methods[] {
        {"SendSignal", "()V", (void*)sendSignal}
    };

    const char *classname = "qt/jni/MyJni";
    jclass clazz;
    QAndroidJniEnvironment env;

    QAndroidJniObject javaClass(classname);
    clazz = env->GetObjectClass(javaClass.object<jobject>());
    qDebug() << "find MyJni - " << clazz;
    bool result = false;
    if(clazz)
    {
        jint ret = env->RegisterNatives(clazz,
                                        methods,
                                        sizeof(methods) / sizeof(methods[0]));
        env->DeleteLocalRef(clazz);
        qDebug() << "RegisterNatives return - " << ret;
        result = ret >= 0;
    }
    if(env->ExceptionCheck()) env->ExceptionClear();
    return result;
}

#endif // ANDROIDJNI

jni的使用方法详解可自行百度,这里主要是注册了一个java函数去发射单例类的信号。
由于使用QAndroidJniObject等类,因此需要在pro文件中添加:

QT += androidextras

在main.cpp中调用registerNativeMethods注册该jni。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    registerNativeMethods();

    Widget w;
    w.show();

    return a.exec();
}

添加一个java文件MyJni.java,在该文件中声明jni注册的java函数即可。

package qt.jni;

public class MyJni {
    public static native void SendSignal();
}

3.在服务中发射信号并在Qt中接收

修改MyService,监听sd卡插拔状态并调用MyJni的SendSignal函数。
MyService.java

package qt.service;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import qt.jni.MyJni;

public class MyService extends Service {

    private static final String TAG = "MyService";
    //File imagepath;

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        Log.i(TAG, "Service on bind");
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Service on create");

        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
        intentFilter.setPriority(1000);
        intentFilter.addDataScheme("file");
        registerReceiver(broadcastRec, intentFilter);
    }

    private final BroadcastReceiver broadcastRec = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            String action = intent.getAction();
            if(action.equals("android.intent.action.MEDIA_MOUNTED")) {
                MyJni.SendSignal();//调用jni发射信号
            }
        }
    };

    @Override
    public void onDestroy() {
        unregisterReceiver(broadcastRec);
    }
}

在widget类中添加一个槽函数,使用信号与槽机制测试单例类的信号是否在MyService中发射成功。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    Singleton *pSin = Singleton::getSingleton();
    connect(pSin, SIGNAL(mySignal()), this, SLOT(getSingletonSignal()));
}

void Widget::getSingletonSignal()
{
    qDebug("I got mySignal");
}

4.测试结果

最后项目文件视图如下。
文件视图
运行该项目,可以在输出中看到jni注册成功,如下。
jni注册成功
插入SD卡,可以在输出中看到widget中的槽成功捕获到单例发射的信号,如下。
信号与槽


源码:servicedemo

猜你喜欢

转载自blog.csdn.net/jun4331247/article/details/51188478
今日推荐