引言
上篇博文详细描述了如何在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注册成功,如下。
插入SD卡,可以在输出中看到widget中的槽成功捕获到单例发射的信号,如下。
源码:servicedemo
扫描二维码关注公众号,回复:
1656100 查看本文章