qt on android之GPS信号的获取

0. 写在最前面

本人参考安晓辉大侠的一篇博文后,做了Qt on android的GSP相关的实验,为了后面不时之需,故而记录下来。

1.Qt on Android GPS系统流程

图1. 系统流程图

如图1所示,系统含两个层面:其一为基于QT的UI,提供启动GPS的按钮(QPushButton),以及显示GPS信号的文本域(QTextBrowser);其二为基于Activity的GPS服务,提供GPS的启动,GPS信号上报等服务。两个层面的交互及C++与Java的交互通过JNI来实现。

系统的整体线索如箭头方式所示:在QT层,按钮被点击后,槽函数startGps被触发,该函数调用Activity层的方法calledByCpp,而calledByCpp方法发送消息到mes handle,消息类型为MSG_STR_GPS_LOC,handle收到消息后,调用函数startAmap启动GPS的定位。GPS启动后,位置的实时信息在函数onLocationChanged()函数中发布,该函数把位置信息通过消息发送给msg handle,其中消息类型为MSG_RPT_GSP_INF,handle再调用native方法reportGpsInfo,就可以把消息发送给QT层。

2.创建Android工程

图2 创建工程

工程命名为QtAndroidGps,且其路径为E:\work\c++\qt,工程创建之后,目录结构如下:

图3. 工程初始文件

在上述自动生成目录下加入文件夹android:

图4. 加入文件夹android后

文件夹android里面包含如下内容:

图5. 文件夹android的内容

可以看出,目录结构与通过eclipse生成的android工程类似,少了assets,bin,gen,res等目录,以及project.properties等文件。

本工程可采用百度与高德的库来定位,其相关的jar包分别为BaiduLBS_Android.jar与Android_Location_V1.1.2.jar,这两个包均放入到e:\work\c++\qt\QtAndroid\android\libs。

同时,在构建工程QtAndroidGps之后,qt会在路径e:\work\c++\qt\之下自动生成目录:

E:\work\c++\qt\build-QtAndroidGps-Android_for_armeabi_v7a_GCC_4_8_Qt_5_4_0-Debug,该目录包含以下文件:

图6. qt构建工程后生成的工程目录

其中,android-build目录包含qt构建出来的android工程,该工程即为完整的android工程:

图7. qt构建工程后生成的android工程目录

可以发现,之前我们人为创建的工程e:\work\c++\qt\QtAndroid\android\里面的文件除了AnroidManifest.xml被整合外,其他文件包括jar包和java文件都被拷贝入:

build-QtAndroidGps-Android_for_armeabi_v7a_GCC_4_8_Qt_5_4_0-Debug。

3.工程文件清单

3.1 E:\work\c++\qt\QtAndroidGps\android\AndroidManifest.xml

……

图8.AndroidManifest.xml

该文件有如上图标注的4个重要点:

① ->与E:\work\c++\qt\QtAndroidGps\android\src中java文件的包路径对应

② ->要把百度与高德的包用起来,必须加入Api-key

③ ->对应Activity的类名

④ ->需要开启GPS定位相关的权限

3.2.1E:\work\c++\qt\QtAndroidGps\mainwindow.h

#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include <QPushButton>namespace Ui {class MainWindow;}class MainWindow : public QMainWindow{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();protected:bool event(QEvent *e);private:Ui::MainWindow *ui;QPushButton *btn; // 点击启动GPSprivate slots:void startGps(); // btn对应的点击槽函数};#endif // MAINWINDOW_H#include "mainwindow.h"#include "ui_mainwindow.h"#include <QAndroidJniObject>#include "CustomEvent.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow){ui->setupUi(this);btn = new QPushButton("start", this);btn->setGeometry(QRect(10, 10, 100, 50));connect(btn, SIGNAL(clicked()), this, SLOT(startGps()));}MainWindow::~MainWindow(){delete ui;}void MainWindow::startGps(){//QAndroidJniObject javaAction = QAndroidJniObject::fromString(url);QAndroidJniObject::callStaticMethod<void>( /* 调用java方法,详细情况请参考qt的帮助文档 */"com/mtn/mes/GpsService","calledByCpp","()V");}bool MainWindow::event(QEvent *e){if(e->type() == CustomEvent::eventType()){ /* 匹配上自定义事件类型 */e->accept();CustomEvent *sce = (CustomEvent*)e;//_resultView->setText(sce->m_arg2);ui->textBrowser->setText(sce->m_arg2); /* 显示GPS信息 */return true;}return QWidget::event(e);}#ifndef CUSTOMEVENT_H#define CUSTOMEVENT_H#include <QEvent>#include <QString>class CustomEvent : public QEvent{public:CustomEvent(int arg1 = 0, const QString &arg2 = QString());~CustomEvent();static Type eventType();int m_arg1;QString m_arg2;private:static Type m_evType;};#endif // CUSTOMEVENT_H#include "CustomEvent.h"QEvent::Type CustomEvent::m_evType = (QEvent::Type)QEvent::None;CustomEvent::CustomEvent(int arg1, const QString &arg2): QEvent(eventType()), m_arg1(arg1), m_arg2(arg2){}CustomEvent::~CustomEvent(){}QEvent::Type CustomEvent::eventType(){if(m_evType == QEvent::None){m_evType = (QEvent::Type)registerEventType(); /* 注册自定义事件,返回m_evType值为qt分配的自定义事件类型 */}return m_evType;}#include "mainwindow.h"#include <QApplication>#include <QDebug>#include <jni.h>#include <QAndroidJniEnvironment>#include <QAndroidJniObject>#include "CustomEvent.h"QObject *main_window = 0;/* 该函数被java的本地方法调用 */static void reportGpsInfo(JNIEnv *env, jobject thiz,int result, jstring data){QString qstrData;const char *nativeString = env->GetStringUTFChars(data, 0);qstrData = nativeString;env->ReleaseStringUTFChars(data, nativeString);QCoreApplication::postEvent(main_window, new CustomEvent(result, qstrData)); /* 发送事件(携带GPS信息)给主窗口,自定义事件类型 */qDebug() << qstrData;}bool registerNativeMethods(){JNINativeMethod methods[] {{"reportGpsInfo", "(ILjava/lang/String;)V", (void*)reportGpsInfo} /* 注册本地方法,java方可调用,详细信息见qt帮助文档 */};const char *classname = "com/mtn/mes/ExtendsQtNative";jclass clazz;QAndroidJniEnvironment env;QAndroidJniObject javaClass(classname);clazz = env->GetObjectClass(javaClass.object<jobject>());qDebug() << "find ExtendsQtNative – " << 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;}int main(int argc, char *argv[]){QApplication a(argc, argv);MainWindow w;CustomEvent::eventType(); // 注册自定义事件,生成自定义事件类型registerNativeMethods(); // 注册本地方法w.show();main_window = qobject_cast<QObject*>(&w);return a.exec();}3.5E:\work\c++\qt\QtAndroidGps\android\src\com\mtn\mes\ExtendsQtNative.javapackage com.mtn.mes;import java.lang.String;public class ExtendsQtNative{public native void reportGpsInfo(int result, String content);}package com.mtn.mes;import java.lang.String;import android.content.Context;import android.content.Intent;import android.app.PendingIntent;import android.os.Handler;import android.os.Message;import android.util.Log;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.net.Uri;import android.location.Criteria;import android.provider.Settings;import android.os.Bundle;import android.os.Environment;import java.io.File;import com.loopj.android.http.AsyncHttpClient;import com.loopj.android.http.AsyncHttpResponseHandler;import android.widget.Toast;import java.util.Date;import android.location.Location;import android.location.LocationListener;import android.location.LocationManager;import com.amap.api.location.AMapLocation;import com.amap.api.location.AMapLocationListener;import com.amap.api.location.LocationManagerProxy;import com.amap.api.location.LocationProviderProxy;import com.baidu.location.BDLocation;import com.baidu.location.BDLocationListener;import com.baidu.location.LocationClient;import com.baidu.location.LocationClientOption;import com.baidu.location.LocationClientOption.LocationMode;public class GpsService extends org.qtproject.qt5.android.bindings.QtActivity{private static GpsService m_instance;private final static String TAG = "GpsService";private final static int MSG_STR_GPS_LOC = 0;private final static int MSG_RPT_GPS_INF = 1;//////////////////////////////////////////////////////////////////定位相关////////////////////////////////////////////////////////////////private LocationManagerProxy aMapManager;public GpsService(){m_instance = this;}public static void calledByCpp() {System.out.println("[0]hello world!");Message msg = new Message();msg.what = MSG_STR_GPS_LOC;m_instance.handler.sendMessage(msg); // 消息触发,启动GPS定位//m_instance.handler.sendEmptyMessage(0); // 消息触发,启动GPS定位}public static void calledByCpp(int arg0) {System.out.println("[1]hello world!");}private void startAmap() {aMapManager = LocationManagerProxy.getInstance(this);/** mAMapLocManager.setGpsEnable(false);* 1.0.2版本新增方法,设置true表示混合定位中包含gps定位,,false表示纯网络定位,默认是true Location* API定位采用GPS和网络混合定位方式* ,第一个参数是定位provider,第二个参数时间最短是2000毫秒,第三个参数距离间隔单位是米,第四个参数是定位监听者*/aMapManager.requestLocationUpdates(LocationProviderProxy.AMapNetwork, 2000, 10, mAMapLocationListener);}private AMapLocationListener mAMapLocationListener = new AMapLocationListener() {@Overridepublic void onStatusChanged(String provider, int status, Bundle extras) {}@Overridepublic void onProviderEnabled(String provider) {}@Overridepublic void onProviderDisabled(String provider) {}@Overridepublic void onLocationChanged(Location location) {}@Overridepublic void onLocationChanged(AMapLocation location) {if (location != null) {Double geoLat = location.getLatitude();Double geoLng = location.getLongitude();String cityCode = "";String desc = "";Bundle locBundle = location.getExtras();if (locBundle != null) {cityCode = locBundle.getString("citycode");desc = locBundle.getString("desc");}String str = ("location ok:(" + geoLng + "," + geoLat + ")"+"\nAccuracy :" + location.getAccuracy() + "Meter" +"\nPositioning:" + location.getProvider() +"\nPositioning time:" + new Date(location.getTime()).toLocaleString() +"\nCity coding :" + cityCode +"\nLocation Description:" + desc +"\nProvince:" + location.getProvince() +"\nCity:" + location.getCity() +"\nDistrict (county):" + location.getDistrict() +"\nRegional Coding:" + location.getAdCode());//Toast.makeText(getApplicationContext(), "高德定位\n" + str, Toast.LENGTH_SHORT).show();// 发送位置信息到handler, hander处再转发给QtMessage msg = new Message();Bundle data = new Bundle();data.putString("value", str);msg.setData(data);msg.what = MSG_RPT_GPS_INF;handler.sendMessage(msg);}}};private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch(msg.what) {case MSG_STR_GPS_LOC: // 消息类型为启动GPS定位m_instance.startAmap();break;case MSG_RPT_GPS_INF: // 消息类型为上送GSP信息ExtendsQtNative m_nativeNotify = new ExtendsQtNative();Bundle data = msg.getData();System.out.println(data.getString("value"));m_nativeNotify.reportGpsInfo(0, data.getString("value")); // 掉用c++方法break;default:System.out.println("msg type error!");break;}}};}

点击下载源码

版权声明:本文为博主原创文章,未经博主允许不得转载。

你可以选择这样的“三心二意”:信心恒心决心;创意乐意。

qt on android之GPS信号的获取

相关文章:

你感兴趣的文章:

标签云: