• qt on android之GPS信号的获取


    0.      写在最前面

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


    1.      Qt on Android GPS系统流程


    图1. 系统流程图

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

    系统的总体线索如箭头方式所看到的:在QT层,button被点击后。槽函数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.      创建Androidproject

    图2 创建project

    project命名为QtAndroidGps,且其路径为E:workc++qt。project创建之后。文件夹结构例如以下:

    图3. project初始文件

    在上述自己主动生成文件夹下增加文件夹android:


    图4. 增加目录android后

    目录android里面包括例如以下内容:


    图5. 目录android的内容

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

    本project可採用百度与高德的库来定位。其相关的jar包分别为BaiduLBS_Android.jar与Android_Location_V1.1.2.jar。这两个包均放入到e:workc++qtQtAndroidandroidlibs。

    同一时候。在构建projectQtAndroidGps之后,qt会在路径e:workc++qt之下自己主动生成文件夹:

    E:workc++qtuild-QtAndroidGps-Android_for_armeabi_v7a_GCC_4_8_Qt_5_4_0-Debug,该文件夹包括下面文件:


    图6. qt构建project后生成的project文件夹

    当中,android-build文件夹包括qt构建出来的androidproject,该project即为完整的androidproject:


    图7. qt构建project后生成的androidproject文件夹

    能够发现,之前我们人为创建的projecte:workc++qtQtAndroidandroid里面的文件除了AnroidManifest.xml被整合外,其它文件包含jar包和java文件都被拷贝入:

    build-QtAndroidGps-Android_for_armeabi_v7a_GCC_4_8_Qt_5_4_0-Debug。

    3.      project文件清单

    3.1 E:workc++qtQtAndroidGpsandroidAndroidManifest.xml


    ......


    图8. AndroidManifest.xml

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

    ①  ->与E:workc++qtQtAndroidGpsandroidsrc中java文件的包路径相应

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

    ③  ->相应Activity的类名

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

    3.2.1 E:workc++qtQtAndroidGpsmainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QPushButton>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    protected:
        bool event(QEvent *e);
    
    private:
        Ui::MainWindow *ui;
        QPushButton *btn; // 点击启动GPS
    
    private slots:
        void startGps(); // btn相应的点击槽函数
    
    };
    
    #endif // MAINWINDOW_H
    
    3.2.2 E:workc++qtQtAndroidGpsmainwindow.cpp

    #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);
    }

    3.3.1 E:workc++qtQtAndroidGpsCustomEvent.h

    #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
    
    3.3.2 E:workc++qtQtAndroidGpsCustomEvent.cpp

    #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;
    }
    
    3.4 E:workc++qtQtAndroidGpsCustomEvent.cpp
    #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.5 E:workc++qtQtAndroidGpsandroidsrccommtnmesExtendsQtNative.java

    package com.mtn.mes;
    import java.lang.String;
    
    public class ExtendsQtNative
    {
        public native void reportGpsInfo(int result, String content);
    }
    
    3.6 E:workc++qtQtAndroidGpsandroidsrccommtnmesGpsService.java

    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() {
    
            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
    
            }
    
            @Override
            public void onProviderEnabled(String provider) {
    
            }
    
            @Override
            public void onProviderDisabled(String provider) {
    
            }
    
            @Override
            public void onLocationChanged(Location location) {
    
            }
    
            @Override
            public 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 + ")"+
                    "
    Accuracy   :" + location.getAccuracy() + "Meter" +
                    "
    Positioning:" + location.getProvider() +
                    "
    Positioning time:" + new Date(location.getTime()).toLocaleString() +
                    "
    City coding :" + cityCode +
                    "
    Location Description:" + desc +
                    "
    Province:" + location.getProvince() +
                    "
    City:" + location.getCity() +
                    "
    District (county):" + location.getDistrict() +
                    "
    Regional Coding:" + location.getAdCode());
    
                    //Toast.makeText(getApplicationContext(), "高德定位
    " + str, Toast.LENGTH_SHORT).show();
    
                    // 发送位置信息到handler, hander处再转发给Qt
                    Message 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() {
    
            @Override
            public 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;
                }
            }
        };
    }

    点击下载源代码

  • 相关阅读:
    C++对象模型
    C/C++内存结构
    第一篇
    Goodbye Steve(19552011)
    DirectX学习笔记_关于Sprite.Draw2D的说明
    Goodbye World!
    js把一个数组的数据平均到几个数组里面
    Django model字段类型清单
    Golang中间件——goredis操作Redis
    Python开发一个短网址生成器
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6915071.html
Copyright © 2020-2023  润新知