删除gps数据gps定位数据

 上传我的文档
 下载
 收藏
请您下载后勿作商用,只可学习交流使用。 本人如有侵犯作者权益,请作者联系本人删除
 下载此文档
正在努力加载中...
卫星定位数据的处理与求分析
下载积分:1250
内容提示:卫星定位数据的处理与求分析
文档格式:PDF|
浏览次数:13|
上传日期: 16:11:58|
文档星级:
该用户还上传了这些文档
卫星定位数据的处理与求分析
官方公共微信30522人阅读
android 基础知识(74)
一、LocationManager
LocationMangager,位置管理器。要想操作定位相关设备,必须先定义个LocationManager。我们可以通过如下代码创建LocationManger对象。
LocationManger locationManager=(LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
二、LocationListener
LocationListener,位置监听,监听位置变化,监听设备开关与状态。
private LocationListener locationListener=new LocationListener() {
* 位置信息变化时触发
public void onLocationChanged(Location location) {
updateView(location);
Log.i(TAG, &时间:&+location.getTime());
Log.i(TAG, &经度:&+location.getLongitude());
Log.i(TAG, &纬度:&+location.getLatitude());
Log.i(TAG, &海拔:&+location.getAltitude());
* GPS状态变化时触发
public void onStatusChanged(String provider, int status, Bundle extras) {
switch (status) {
//GPS状态为可见时
case LocationProvider.AVAILABLE:
Log.i(TAG, &当前GPS状态为可见状态&);
//GPS状态为服务区外时
case LocationProvider.OUT_OF_SERVICE:
Log.i(TAG, &当前GPS状态为服务区外状态&);
//GPS状态为暂停服务时
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Log.i(TAG, &当前GPS状态为暂停服务状态&);
* GPS开启时触发
public void onProviderEnabled(String provider) {
Location location=lm.getLastKnownLocation(provider);
updateView(location);
* GPS禁用时触发
public void onProviderDisabled(String provider) {
updateView(null);
三、Location
Location,位置信息,通过Location可以获取时间、经纬度、海拔等位置信息。上面采用locationListener里面的onLocationChanged()来获取location,下面讲述如何主动获取location。
Location location=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
system.out.println(&时间:&+location.getTime());
system.out.println(&经度:&+location.getLongitude());
注意:Location location=new Location(LocationManager.GPS_PROVIDER)方式获取的location的各个参数值都是为0。
四、GpsStatus.Listener
GpsStatus.Listener ,GPS状态监听,包括GPS启动、停止、第一次定位、卫星变化等事件。
//状态监听
GpsStatus.Listener listener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int event) {
switch (event) {
//第一次定位
case GpsStatus.GPS_EVENT_FIRST_FIX:
Log.i(TAG, &第一次定位&);
//卫星状态改变
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
Log.i(TAG, &卫星状态改变&);
//获取当前状态
GpsStatus gpsStatus=lm.getGpsStatus(null);
//获取卫星颗数的默认最大值
int maxSatellites = gpsStatus.getMaxSatellites();
//创建一个迭代器保存所有卫星
Iterator&GpsSatellite& iters = gpsStatus.getSatellites().iterator();
int count = 0;
while (iters.hasNext() && count &= maxSatellites) {
GpsSatellite s = iters.next();
count++;
System.out.println(&搜索到:&+count+&颗卫星&);
//定位启动
case GpsStatus.GPS_EVENT_STARTED:
Log.i(TAG, &定位启动&);
//定位结束
case GpsStatus.GPS_EVENT_STOPPED:
Log.i(TAG, &定位结束&);
//绑定监听状态
lm.addGpsStatusListener(listener);
五、GpsStatus
GpsStatus,GPS状态信息,上面在卫星状态变化时,我们就用到了GpsStatus。
GpsStatus gpsStatus = locationManager.getGpsStatus(null); // 获取当前状态
//获取默认最大卫星数
int maxSatellites = gpsStatus.getMaxSatellites();
//获取第一次定位时间(启动到第一次定位)
int costTime=gpsStatus.getTimeToFirstFix();
//获取卫星
Iterable&GpsSatellite& iterable=gpsStatus.getSatellites();
//一般再次转换成Iterator
Iterator&GpsSatellite& itrator=iterable.iterator();
六、GpsSatellite
GpsSatellite,定位卫星,包含卫星的方位、高度、伪随机噪声码、信噪比等信息。
//获取卫星
Iterable&GpsSatellite& iterable=gpsStatus.getSatellites();
//再次转换成Iterator
Iterator&GpsSatellite& itrator=iterable.iterator();
//通过遍历重新整理为ArrayList
ArrayList&GpsSatellite& satelliteList=new ArrayList&GpsSatellite&();
int count=0;
int maxSatellites=gpsStatus.getMaxSatellites();
while (itrator.hasNext() && count &= maxSatellites) {
GpsSatellite satellite = itrator.next();
satelliteList.add(satellite);
count++;
System.out.println(&总共搜索到&+count+&颗卫星&);
//输出卫星信息
for(int i=0;i&satelliteList.size();i++){
//卫星的方位角,浮点型数据
System.out.println(satelliteList.get(i).getAzimuth());
//卫星的高度,浮点型数据
System.out.println(satelliteList.get(i).getElevation());
//卫星的伪随机噪声码,整形数据
System.out.println(satelliteList.get(i).getPrn());
//卫星的信噪比,浮点型数据
System.out.println(satelliteList.get(i).getSnr());
//卫星是否有年历表,布尔型数据
System.out.println(satelliteList.get(i).hasAlmanac());
//卫星是否有星历表,布尔型数据
System.out.println(satelliteList.get(i).hasEphemeris());
//卫星是否被用于近期的GPS修正计算
System.out.println(satelliteList.get(i).hasAlmanac());
为了便于理解,接下来模拟一个案例,如何在程序代码中使用GPS获取位置信息。
第一步:新建一个Android工程项目,命名为mygps,目录结构如下
第二步:修改main.xml布局文件,修改内容如下:
&?xml version=&1.0& encoding=&utf-8&?&
&LinearLayout xmlns:android=&/apk/res/android&
android:orientation=&vertical&
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&&
&EditText android:layout_width=&fill_parent&
android:layout_height=&wrap_content&
android:cursorVisible=&false&
android:editable=&false&
android:id=&@+id/editText&/&
&/LinearLayout&
第三步:实用Adnroid平台的GPS设备,需要添加上权限
&uses-permission android:name=&android.permission.ACCESS_FINE_LOCATION&/&
&uses-permission android:name=&android.permission.ACCESS_COARSE_LOCATION&/&
第四步:修改核心组件activity,修改内容如下
package jason.
import java.util.I
import android.app.A
import android.content.C
import android.content.I
import android.location.C
import android.location.GpsS
import android.location.GpsS
import android.location.L
import android.location.LocationL
import android.location.LocationM
import android.location.LocationP
import android.os.B
import android.provider.S
import android.util.L
import android.widget.EditT
import android.widget.T
public class MainActivity extends Activity {
private EditText editT
private LocationM
private static final String TAG = &GpsActivity&;
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
lm.removeUpdates(locationListener);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText);
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 判断GPS是否正常启动
if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, &请开启GPS导航...&, Toast.LENGTH_SHORT).show();
// 返回开启GPS导航设置界面
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, 0);
// 为获取地理位置信息时设置查询条件
String bestProvider = lm.getBestProvider(getCriteria(), true);
// 获取位置信息
// 如果不设置查询要求,getLastKnownLocation方法传人的参数为LocationManager.GPS_PROVIDER
Location location = lm.getLastKnownLocation(bestProvider);
updateView(location);
// 监听状态
lm.addGpsStatusListener(listener);
// 绑定监听,有4个参数
// 参数1,设备:有GPS_PROVIDER和NETWORK_PROVIDER两种
// 参数2,位置信息更新周期,单位毫秒
// 参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息
// 参数4,监听
// 备注:参数2和3,如果参数3不为0,则以参数3为准;参数3为0,则通过时间来定时更新;两者为0,则随时刷新
// 1秒更新一次,或最小位移变化超过1米更新一次;
// 注意:此处更新准确度非常低,推荐在service里面启动一个Thread,在run中sleep(10000);然后执行handler.sendMessage(),更新位置
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, locationListener);
// 位置监听
private LocationListener locationListener = new LocationListener() {
* 位置信息变化时触发
public void onLocationChanged(Location location) {
updateView(location);
Log.i(TAG, &时间:& + location.getTime());
Log.i(TAG, &经度:& + location.getLongitude());
Log.i(TAG, &纬度:& + location.getLatitude());
Log.i(TAG, &海拔:& + location.getAltitude());
* GPS状态变化时触发
public void onStatusChanged(String provider, int status, Bundle extras) {
switch (status) {
// GPS状态为可见时
case LocationProvider.AVAILABLE:
Log.i(TAG, &当前GPS状态为可见状态&);
// GPS状态为服务区外时
case LocationProvider.OUT_OF_SERVICE:
Log.i(TAG, &当前GPS状态为服务区外状态&);
// GPS状态为暂停服务时
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Log.i(TAG, &当前GPS状态为暂停服务状态&);
* GPS开启时触发
public void onProviderEnabled(String provider) {
Location location = lm.getLastKnownLocation(provider);
updateView(location);
* GPS禁用时触发
public void onProviderDisabled(String provider) {
updateView(null);
// 状态监听
GpsStatus.Listener listener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int event) {
switch (event) {
// 第一次定位
case GpsStatus.GPS_EVENT_FIRST_FIX:
Log.i(TAG, &第一次定位&);
// 卫星状态改变
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
Log.i(TAG, &卫星状态改变&);
// 获取当前状态
GpsStatus gpsStatus = lm.getGpsStatus(null);
// 获取卫星颗数的默认最大值
int maxSatellites = gpsStatus.getMaxSatellites();
// 创建一个迭代器保存所有卫星
Iterator&GpsSatellite& iters = gpsStatus.getSatellites()
.iterator();
int count = 0;
while (iters.hasNext() && count &= maxSatellites) {
GpsSatellite s = iters.next();
count++;
System.out.println(&搜索到:& + count + &颗卫星&);
// 定位启动
case GpsStatus.GPS_EVENT_STARTED:
Log.i(TAG, &定位启动&);
// 定位结束
case GpsStatus.GPS_EVENT_STOPPED:
Log.i(TAG, &定位结束&);
* 实时更新文本内容
* @param location
private void updateView(Location location) {
if (location != null) {
editText.setText(&设备位置信息\n\n经度:&);
editText.append(String.valueOf(location.getLongitude()));
editText.append(&\n纬度:&);
editText.append(String.valueOf(location.getLatitude()));
// 清空EditText对象
editText.getEditableText().clear();
* 返回查询条件
private Criteria getCriteria() {
Criteria criteria = new Criteria();
// 设置定位精确度 Criteria.ACCURACY_COARSE比较粗略,Criteria.ACCURACY_FINE则比较精细
criteria.setAccuracy(Criteria.ACCURACY_FINE);
// 设置是否要求速度
criteria.setSpeedRequired(false);
// 设置是否允许运营商收费
criteria.setCostAllowed(false);
// 设置是否需要方位信息
criteria.setBearingRequired(false);
// 设置是否需要海拔信息
criteria.setAltitudeRequired(false);
// 设置对电源的需求
criteria.setPowerRequirement(Criteria.POWER_LOW);
第五步:运行效果如下,嘿嘿,用的小米3的工程机做的测试,米3 发布会吹嘘的搜星速度确实很快:
作者:jason0539
博客:(转载请说明出处)
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2506954次
积分:17016
积分:17016
排名:第436名
原创:183篇
转载:12篇
评论:741条
====原创====
====思考====
你花六块八块买个盒饭吃,觉得很节省,有人在路边买了七毛钱馒头吞咽后步履匆匆;
你八点起床看书,觉得很勤奋,上微博发现曾经的同学八点就已经在面对繁重的工作;
你周六补个课,觉得很累,打个电话才知道许多朋友都连续加班了一个月。
亲爱的,你真的还不够苦,不够勤奋和努力。
(1)(1)(1)(1)(1)(7)(18)(4)(1)(1)(2)(2)(3)(13)(14)(6)(5)(9)(12)(55)(22)(7)(2)(1)(2)(3)
====思想====
====内容====经常看到有人抱怨说:“我在奥森10公里健步道上走了一整圈,可我手机上的运动记录只有8公里!”“我正在橘子洲跑步,可我手机上的GPS显示我在163爬山!”“一进山我就打开了轨迹记录软件,爬了一天的山,现在都出山要回家了,还是没能定位。今天的轨迹又没记录下来,不知道实际走了多少公里。”如果手机有并且开启着卫星定位系统(现在可用的不止有美国的GPS,还有俄国的GLONASS、中国的北斗BeiDou,习惯上统称GPS,但你的手机上不一定都有)的话,这就是所谓的GPS信号不稳定或者搜不到星了,单独使用设备GPS定位硬件常常会出现这种情况。原因在于GPS接收器件只会被动地GPS卫星发来的定位信号,如果你所在的位置不够开阔,比如周围有高大建筑物、峭壁甚至树木遮拦,接收器件常常收不到足够多的卫星信号,就无法计算出准确的位置信息。你不必一味埋怨你的手机烂,遇到这种情况————其实也不是完全没辙。因为手机定位并不单独依赖GPS卫星,一般还使用WLAN和移动网络,这就是所谓的辅助GPS,或称A-GPS、AGPS。有了它,就很少出现位置漂移或搜不到星的情况了。现在很多手机应用都有室内导航功能,在封闭的商场、体育馆所和地铁站里都能定位,这些地方根本不可能接收到卫星信号,用的就是A-GPS。使用AGPS很简单,手机上一般默认是启用的,耗电量很小,不必为了省电而关闭这项功能;真要想省电的话,关闭设备的GPS功能(下图中【耗电量低/节电】模式),但定位精度就很差了,野外没有数据信号的地方会完全无法定位。可以在【手机设置】【定位服/位置信息】里进行如下操作查验、设置AGPS(手机不同,具体文字/版式/内容可能有差别):&1.【访问我的位置信息/开启】:选中&2.【定位模式/位置信息模式】【准确度高/高精确度】:选中& & &3.如果有【A-GPS设置】选项,可进一步设置【数据网络使用】选项。因为流量消耗很小,建议开启【本地和漫游网络均开启A-GPS】,但如果漫游流量很贵(比如在境外时)可以只选本地网络开启,或者干脆关闭手机的数据网络功能。无论使用地是否有WiFi,一定要打开该功能,如果没打开,很多地图应用都会提示你打开的。——可是我在野山里,别说无线WiFi了,连手机信号都没有,用不上A-GPS啊。可能是这样,因为不少地图应用只是在需要时才利用数据网络下载AGPS数据。但是,但是,但是——重要的“但是”说三遍(现在已经四遍了∶),有些应用可以提前下载A-GPS数据。这里介绍一个:GPS状态,英文名GPS Status,提供者是MobiWIA的EclipSim(MobiWIA - EclipSim),来自匈牙利的布达佩斯。GPS状态能实时搜索卫星定位信号,显示当前所在位置的GPS信息,包括“卫星的位置和信号强度、精度、速度、加速度、海拔高度、方位、俯仰角、滚转角和电池状态”,具有“指南针和地理北极功能,水平工具,标记或分享你的位置并在以后导航回来。”GPS快速定位只是它的辅助功能,能“重置或定期下载A-GPS(辅助GPS)数据进行更快的定位”,供其他需要定位的手机软件使用。它有免费版和专业版Pro两个版本,免费版功能有限制,但一般够用了,代价是页面上有广告条,不过很少变化,用起来并不碍事。其实专业版GPS Status Pro的价格并不贵,花钱买来也还承受得起。(PS:在Google Play商店,新年之前正在半价优惠呢,我买了。)GPS状态是一个独立的安卓手机应用,使用起来很简单,用过就知道。至于保持其他应用快速定位,就更简单了:安装了GPS状态的手机,打开其他地图应用时,状态栏上会闪出GPS状态的图标,应用欻的一下就定位了。当你去往野外,不要着急启动飞行模式,在就要离开有数据网络的时候,打开一下GPS状态,看到A-GPS数据已下载,这一天你的定位就基本保证了。当然,如果你长时间处于不见天日、又没有网络,GPS状态也无能为力帮你定位。很多安卓应用市场上都有GPS状态这个应用供下载,记住一定要是MobiWIA - EclipSim提供的,其他有相同或类似名称的有不少,但未必有A-GPS数据预存功能。另外,强烈建议你去安卓应用的大本营Google Play上安装,直达链接是〖注〗:个中原因,一说你就明白:有人盗版,把应用内中的广告源篡改成了别的,广告特别多,不住地切换,眼都要看花了。这只是外观,盗版的背地里还在干什么不想见人的事儿,不要问我。〖注〗Google Play网站不提供直接下载,需要使用其手机客户端Google Play Store(Play商店)并且登录Google账号后安装,目前需要科学上网。如果你手机上没有预装Play商店,请自行搜索(首选你的手机制造商的官网)查找安装方法;如果安装后无法使用或根本无法安装,则你的手机还需要越狱,风险自负。
我1300元买的新手机没找到使用辅助GPS,即只有图中的前三项,怎么破?
左图的前三项?选中第一项“准确度高”/“高精确度”就行了,已经包括了AGPS的,具体设置聊胜于无,没多大意义。右图也是只有钱三项的。
回复了话题
回复了话题
请选择违反的法度
出走社网络行为规范出走课题公约出走社社民分级方案出走社公共机构组织办法出走社公职人员行为准则出走社栏目定位出走课题余款处置方案出走社社民积分制度出走社活动预付款管理办法出走课题强度评估方案出走社“准实名制”实施方案出走社规避制度出走课题应急联络条例出走社关于课题中代购车票的规则出走社野外安全气象标准出走社反占坑条例出走社反“邂逅”条例社名使用规则出走社保护性限制强度办法出走社过滤词和敏感词管理办法出走社保举制度出走社宪政预备时期实施方案出走社冗余账号清理办法出走社网站域名及服务器空间管理办法出走社反傀儡账号法案出走社仲裁规则出走社投票通则出走社网站维护基金管理细则出走社网站事故紧急预案未成年人分担出走课题实施条例出走社宪章出走社限制野外用火条例公民个人发起民意调查数量控制法案出走社全民公决投票规则出走社议事会议事规则理事工作细则
请选择违反的法度
出走社网络行为规范出走课题公约出走社社民分级方案出走社公共机构组织办法出走社公职人员行为准则出走社栏目定位出走课题余款处置方案出走社社民积分制度出走社活动预付款管理办法出走课题强度评估方案出走社“准实名制”实施方案出走社规避制度出走课题应急联络条例出走社关于课题中代购车票的规则出走社野外安全气象标准出走社反占坑条例出走社反“邂逅”条例社名使用规则出走社保护性限制强度办法出走社过滤词和敏感词管理办法出走社保举制度出走社宪政预备时期实施方案出走社冗余账号清理办法出走社网站域名及服务器空间管理办法出走社反傀儡账号法案出走社仲裁规则出走社投票通则出走社网站维护基金管理细则出走社网站事故紧急预案未成年人分担出走课题实施条例出走社宪章出走社限制野外用火条例公民个人发起民意调查数量控制法案出走社全民公决投票规则出走社议事会议事规则理事工作细则1220人阅读
Android源码(38)
Android:V4.2.2
Source Insight
在漫长的Android源码编译等待过程中,想起之前写过一部分的Android定位实现的探究小品,于是继续探究。
注:代码都是片段化的代码,用来提纲挈领的说明问题。
定位的基础知识:
1、定位芯片和CPU之间通过串口进行通信
2、串口和CPU之间传输的是ASCII格式的NMEA(National Marine Electronics Association)信息,如:
$GPGGA,,,S,,E,1,04,24.4,19.7,M,,,,0000*1F
$GPGLL,,S,,E,,A*2D
$GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,069,,13,32,252,45*70
$GPRMC,,A,,S,,E,0.00,89.68,211200,,*25
基于以上两点,要探知定位数据从GPS芯片到应用层的流程,最好的途径就是从应用层输出NEMA信息的地方开始。
NMEA资料参见:
一、GPS定位的应用层实现
Luckily,在应用层我们可以通过onNmeaReceived()方法获取到NMEA信息,如下Code Fragment:
public class GpsTestActivity extends ActionBarActivity {
/* Other Codes */
/** 获取系统的定位服务,记得在AndroidManifest中赋予定位方面的权限:
* &uses-permission android:name=&android.permission.ACCESS_FINE_LOCATION&/&
* &uses-permission android:name=&android.permission.ACCESS_LOCATION_EXTRA_COMMANDS&/&
* &uses-permission android:name=&android.permission.ACCESS_COARSE_LOCATION&/&
LocationManager mLocationService = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mLocationService.addNmeaListener(mNmeaListener);
private GpsStatus.NmeaListener mNmeaListener = new NmeaListener() {
public void onNmeaReceived(long timestamp, String nmea) {
System.out.println(nmea + &\n&);
二、GPS定位的Framework层实现
GpsStatus.NmeaListener是一个接口类,来自GpsStatus.java文件:
frameworks\base\location\java\android\location\GpsStatus.java
* Used for receiving NMEA sentences from the GPS.
* NMEA 0183 is a standard for communicating with marine electronic devices
* and is a common method for receiving data from a GPS, typically over a serial port.
* See &a href=&http://en.wikipedia.org/wiki/NMEA_0183&&NMEA 0183&/a& for more details.
* You can implement this interface and call {@link LocationManager#addNmeaListener}
* to receive NMEA data from the GPS engine.
public interface NmeaListener {
void onNmeaReceived(long timestamp, String nmea);
}在上述App中,我们的应用程序实现了该方法,一旦NMEA数据到来,onNmeaReceived()方法就被调用一次,我们在Console上可以看到原始的NEMA信息。
那么接下来,就要寻找nmea数据的来源了。
mNmeaListener通过LocationManager类的addNmeaListener()方法进行注册(register):
frameworks\base\location\java\android\location\LocationManager.java
* Adds an NMEA listener.
* @param listener a {@link GpsStatus.NmeaListener} object to register
* @return true if the listener was successfully added
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
/* mNmeaListeners是LocationManager类的成员变量:
* private final HashMap&GpsStatus.NmeaListener, GpsStatusListenerTransport& mNmeaListeners =
new HashMap&GpsStatus.NmeaListener, GpsStatusListenerTransport&();
if (mNmeaListeners.get(listener) != null) {
// listener is already registered
GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
result = mService.addGpsStatusListener(transport);
if (result) {
mNmeaListeners.put(listener, transport);
} catch (RemoteException e) {
Log.e(TAG, &RemoteException in registerGpsStatusListener: &, e);
}这里,先检测定义的NmeaListener有没有被注册过,若果没有,注册之。
注册到哪里去了呢?
由mNmeaListeners成员的定义可知,和GpsStatus.NmeaListener进行关联的是GpsStatusListenerTransport,而它是LocationManager类的一个内部类。
只看相关的部分:
// This class is used to send GPS status events to the client's main thread.
private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
private final GpsStatus.NmeaListener mNmeaL
// This must not equal any of the GpsStatus event IDs
private static final int NMEA_RECEIVED = 1000;
private class Nmea {
Nmea(long timestamp, String nmea) {
mTimestamp =
private ArrayList&Nmea& mNmeaB
//G psStatusListenerTransport(GpsStatus.Listener listener){}
GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
mNmeaListener =
mListener =
mNmeaBuffer = new ArrayList&Nmea&();
public void onNmeaReceived(long timestamp, String nmea) {
if (mNmeaListener != null) {
synchronized (mNmeaBuffer) {
mNmeaBuffer.add(new Nmea(timestamp, nmea));
Message msg = Message.obtain();
msg.what = NMEA_RECEIVED;
// remove any NMEA_RECEIVED messages already in the queue
mGpsHandler.removeMessages(NMEA_RECEIVED);
mGpsHandler.sendMessage(msg);
private final Handler mGpsHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == NMEA_RECEIVED) {
synchronized (mNmeaBuffer) {
int length = mNmeaBuffer.size();
for (int i = 0; i & i++) {
Nmea nmea = mNmeaBuffer.get(i);
mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
mNmeaBuffer.clear();
// synchronize on mGpsStatus to ensure the data is copied atomically.
}在GpsStatusListenerTransport类中:
定义一个Nmea类型的链表mNmeaBuffer,一旦onNmeaReceived()接收到NMEA数据,新数据被加载到链表mNmeaBuffer中(mNmeaBuffer.add(new Nmea(timestamp, nmea))),然手置消息标志为NMEA_RECEIVED(msg.what = NMEA_RECEIVED)。
mGpsHandler对上述NMEA_RECEIVED消息进行处理,最终把传过来的NMEA数据发往应用层GpsTestActivity中的onNmeaReceived()。
那么,GpsStatusListenerTransport类中onNmeaReceived(long timestamp, String nmea)方法的nmea数据有谁提供呢?
GpsStatusListenerTransport类继承自IGpsStatusListener,由类前的字符&I&我们得知,它是一个扩展名为.aidl的文件。
AIDL:AIDL机制用来完成在进程之间进行通信(在Android中不允许进程间共享数据),它的详细知识另外Google之。
这里,我们再次见到了onNmeaReceived():
rameworks\base\location\java\android\location\IGpsStatusListener.aidl
oneway interface IGpsStatusListener
void onGpsStarted();
void onGpsStopped();
void onFirstFix(int ttff);
void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, in float[] elevations, in float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask);
void onNmeaReceived(long timestamp, String nmea);
oneway关键字是用来修饰远程调用行为。使用该关键词时,远程调用不是阻塞的,它只是发送事物数据并立即返回。接口的最终实现是把普通的远程调用按照Binder线程池的调用规则来接收,如果oneway是使用在本地调用上,那么不会有任何影响,并且调用依然是异步的。
下面,探究必须进入第三层。
三、GPS定位的Lib层实现
和IGpsStatusListener接头的是GpsLocationProvider类:
frameworks\base\services\java\com\android\server\location\GpsLocationProvider.java
public class GpsLocationProvider implements LocationProviderInterface {
// 此处省略1000+N行
private ArrayList&Listener& mListeners = new ArrayList&Listener&();
private final class Listener implements IBinder.DeathRecipient {
final IGpsStatusListener mL
Listener(IGpsStatusListener listener) {
mListener =
public void binderDied() {
if (DEBUG) Log.d(TAG, &GPS status listener died&);
synchronized (mListeners) {
mListeners.remove(this);
if (mListener != null) {
mListener.asBinder().unlinkToDeath(this, 0);
* called from native code to report NMEA data received
private void reportNmea(long timestamp) {
synchronized (mListeners) {
int size = mListeners.size();
if (size & 0) {
// don't bother creating the String if we have no listeners
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
String nmea = new String(mNmeaBuffer, 0, length);
for (int i = 0; i & i++) {
Listener listener = mListeners.get(i);
listener.mListener.onNmeaReceived(timestamp, nmea);
} catch (RemoteException e) {
Log.w(TAG, &RemoteException in reportNmea&);
mListeners.remove(listener);
// adjust for size of list changing
}GPS定位功能最终需要调用硬件实现,操作硬件就必须通过C/C++完成,GpsLocationProvider中包含许多native方法,采用JNI机制为上层提供服务。
在上面的Code Frame中,通过调用本地方法native_read_nmea()获取到NMEA数据,然后传数据到IGpsStatusListener接口类的onNmeaReceived()方法。
reportNmea()是被JNI方法回调的方法,在 JNI 的实现中,通过这些方法的回调来传递JNI层的执行结果。
源码编译出错,解决问题去。。。
native_read_nmea()在GpsLocationProvider类中定义:
private native int native_read_nmea(byte[] buffer, int bufferSize);native指明它是本地方法,和它对应的C/C++文件的实现是:
static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jbyteArray nmeaArray, jint buffer_size);How?Next...
frameworks\base\services\jni\com_android_server_location_GpsLocationProvider.cpp
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
/* other members... */
{&native_read_nmea&, &([BI)I&, (void*)android_location_GpsLocationProvider_read_nmea},
/* other members... */
};JNINativeMethod是Android中采用的Java和C/C++函数的映射方式,并在其中描述了函数的参数和返回值:
typedef struct {
const char*
// Java文件中的本地方法
const char* // 述了函数的参数和返回值
// 指针,指向具体的C/C++函数
} JNINativeM详细内容这里还是不展开了。
来看android_location_GpsLocationProvider_read_nmea()的实现:
static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
jbyteArray nmeaArray, jint buffer_size)
// this should only be called from within a call to reportNmea
jbyte* nmea = (jbyte *)env-&GetPrimitiveArrayCritical(nmeaArray, 0);
int length = sNmeaStringL
if (length & buffer_size)
length = buffer_
memcpy(nmea, sNmeaString, length);
env-&ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
}虽然不清楚JNI深入含义,但这个函数意思还是挺明显的,我们推断:
第5行:用来动态分配内存,nmea指向获取到的内存区域,同时把nmea和nmeaArray进行关联;
第6行:sNmeaStringLength指示一次从串口读取到的字节长度
第7、8行:在Java中调用native_read_nmea()方法时指明了我们需要取的数据长度,所以,如果从串口实际读取的数据长度大于我们需要的,我们对串口数据进行截取:即,只取指定长度的数据;
第9行:从串口读出的数据存在sNmeaString中,这里Copy到nmea指向的内存区域;
第10行:nmea指向的内存区域中的数据交给nmeaArray,然后释放nmea指向的内存空间。这里也可以看到,函数调用是通过nmeaArray传递NMEA数据的
下面应该看sNmeaStringLength、sNmeaString的设置过程:
static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
JNIEnv* env = AndroidRuntime::getJNIEnv();
// The Java code will call back to read these values
// We do this to avoid creating unnecessary String objects
sNmeaString =
sNmeaStringLength =
env-&CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}method_reportNmea、、、有没有熟悉的感觉?
对,在GpsLocationProvider类中见过reportNmea(long timestamp)函数。
下面的代码片段表明,method_reportNmea()和reportNmea()是绑定在一起的,调用C/C++函数method_reportNmea,也就间接调用Java的reportNmea()方法。这中间的机制,就是JNI!
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
/* other definitions... */
method_reportNmea = env-&GetMethodID(clazz, &reportNmea&, &(J)V&);
/* other definitions... */
}而method_reportNmea是在nmea_callback()函数中被调用的,哪里又调用nmea_callback()函数呢?
Let's go to neXt Layer...
四、GPS定位HAL层的实现
所谓Android的HAL层,也就是是Linux的应用程序。至于串口具体配置,比如寄存器配置、数据收发等芯片级实现,是在在Linux内核里的。
com_android_server_location_GpsLocationProvider.cpp文件中另外出现nmea_callback的地方是:
GpsCallbacks sGpsCallbacks = {
sizeof(GpsCallbacks),
location_callback,
status_callback,
sv_status_callback,
nmea_callback,
set_capabilities_callback,
acquire_wakelock_callback,
release_wakelock_callback,
create_thread_callback,
request_utc_time_callback,
};GpsCallbacks结构体封装了所有需要回调的函数(确切的说是函数指针),sGpsCallbacks调用关系:
static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
// this must be set before calling into the HAL library
if (!mCallbacksObj)
mCallbacksObj = env-&NewGlobalRef(obj);
// fail if the main interface fails to initialize
if (!sGpsInterface || sGpsInterface-&init(&sGpsCallbacks) != 0)
/* other codes */
}而android_location_GpsLocationProvider_init()在GpsLocationProvider类中调用native_init()时被调用:
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{&native_init&, &()Z&, (void*)android_location_GpsLocationProvider_init}
}这里,我们找到了和上层的关系,和下层如何打交道呢?
下面需要贴一大段代码:/** Represents the standard GPS interface. */
typedef struct {
/** set to sizeof(GpsInterface) */
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
(*init)( GpsCallbacks* callbacks );
/** Starts navigating. */
(*start)( void );
/** Stops navigating. */
(*stop)( void );
/** Closes the interface. */
(*cleanup)( void );
/** Injects the current time. */
(*inject_time)(GpsUtcTime time, int64_t timeReference,
int uncertainty);
/** Injects current location from another location provider
(typically cell ID).
latitude and longitude are measured in degrees
expected accuracy is measured in meters
(*inject_location)(double latitude, double longitude, float accuracy);
* Specifies that the next call to start will not use the
* information defined in the flags. GPS_DELETE_ALL is passed for
* a cold start.
(*delete_aiding_data)(GpsAidingData flags);
* min_interval represents the time between fixes in milliseconds.
* preferred_accuracy represents the requested fix accuracy in meters.
* preferred_time represents the requested time to first fix in milliseconds.
(*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,
uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);
/** Get a pointer to extension information. */
const void* (*get_extension)(const char* name);
} GpsIGpsInterface结构体封装了GPS实现的标准接口——接口,注意!接口不就时用来连接两端的吗?一端是com_android_server_location_GpsLocationProvider.cpp文件里的实现,那另一端就是。。。都探到这个地步了,另一端应该是串口方式直接和GPS芯片打交道的Linux驱动了吧?
确是,但是还需要一个媒介:
struct gps_device_t {
struct hw_device_
* Set the provided lights to the provided values.
* Returns: 0 on succes, error code on failure.
const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev);
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
hw_module_t*
/* other codes..*/
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
hw_device_t*
err = module-&methods-&open(module, GPS_HARDWARE_MODULE_ID, &device);
if (err == 0) {
gps_device_t* gps_device = (gps_device_t *)
sGpsInterface = gps_device-&get_gps_interface(gps_device);
/* other codes..*/
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{&class_init_native&, &()V&, (void *)android_location_GpsLocationProvider_class_init_native},
}GpsLocationProvider.java通过class_init_native的调用实现对C/C++文件中android_location_GpsLocationProvider_class_init_native的调用;
com_android_server_location_GpsLocationProvider.cpp通过gps_device_t获取操作GPS芯片的接口。How????
重点来了:GPS_HARDWARE_MODULE_ID
对,就是GPS_HARDWARE_MODULE_ID!
ardware\qcom\gps\loc_api\libloc_api\gps.c
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = GPS_HARDWARE_MODULE_ID,
.name = &loc_api GPS Module&,
.author = &Qualcomm USA, Inc.&,
.methods = &gps_module_methods,
};有木有?GPS_HARDWARE_MODULE_ID!
hardware\qcom\gps\loc_api\libloc_api\gps.c
extern const GpsInterface* gps_get_hardware_interface();
const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
return gps_get_hardware_interface();
static int open_gps(const struct hw_module_t* module, char const* name,
struct hw_device_t** device)
struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
memset(dev, 0, sizeof(*dev));
dev-&common.tag = HARDWARE_DEVICE_TAG;
dev-&common.version = 0;
dev-&common.module = (struct hw_module_t*)
dev-&get_gps_interface = gps__get_gps_
*device = (struct hw_device_t*)
static struct hw_module_methods_t gps_module_methods = {
.open = open_gps
};流程很清楚了:
gps_get_hardware_interface()函数在驱动程序中实现
&& &——在gps__get_gps_interface()中被调用
&& &&& &——在open_gps()被调用
&& &&& &&& &——在gps_module_methods中例化
&& &&& &&& &&& &——HAL_MODULE_INFO_SYM
const GpsInterface* gps_get_hardware_interface()函数在其他C文件实现,该C文件是和Linux驱动打交道的应用程序。基本功能:
1、open处理器CPU和GPS芯片连接的串口;
2、read串口NEMA数据,并解析;
3、根据上层传进来的回调函数,打包数据,调用相应Callback,进而发送到Android应用层。
static const GpsInterface
mGpsInterface = {
.size =sizeof(GpsInterface),
.init = gps_init,
|--1、接收从上层传下来的GpsCallbacks变量,用它初始化GpsState-&callbacks成员
|--2、GpsState结构体的其他成员初始化
|--3、GpsState-&init状态设置为:STATE_INIT
|--4、最重要:启动GPS线程,进行数据的读取、处理:
state-&thread = state-&callbacks.create_thread_cb(&gps&, gps_state_thread, state);
--gps_create_thread create_thread_
--typedef pthread_t (* gps_create_thread)(const char* name, void (*start)(void *), void* arg);
.start = gps_start,
--设置GPS的状态为开始:GPS_STATUS_SESSION_BEGIN
.stop = gps_stop,
--设置GPS的状态为结束:GPS_STATUS_SESSION_END
.cleanup = gps_cleanup,
--退出需要进行的一些清理工作,如GpsState-&init = STATE_QUIT,GpsCallbacks指针归null,信号量回收
.inject_time = gps_inject_time,
--可为空函数
.inject_location = gps_inject_location,
--可为空函数
.delete_aiding_data = gps_delete_aiding_data,
--可为空函数
.set_position_mode = gps_set_position_mode,
--设置GPS工作模式:单GPS、单BD、GPS/BD双系统
.get_extension = gps_get_extension,
--定位之外的扩展功能实现
state-&thread = state-&callbacks.create_thread_cb(&gps&, gps_state_thread, state);
--static void gps_state_thread(void*
1、state通过arg参数传入函数
2、创建了Time和Nmea数据处理两个线程
state-&nmea_thread = state-&callbacks.create_thread_cb(&nmea_thread&, gps_nmea_thread, state);
--static void gps_nmea_thread(void*
--gps_opentty(state);
nmea_reader_init(reader);
--nmea_reader_parse(NmeaReader*
if (gps_state-&callbacks.nmea_cb) {
gettimeofday(&tv,NULL);
mytimems = tv.tv_sec * 1000 + tv.tv_usec / 1000;
gps_state-&callbacks.nmea_cb(mytimems, r-&in, r-&pos);
D(&reader_parse. %.*s &, r-&pos, r-&in );
我们是从APP层NMEA信息输出自定向下分析的,APP层信息输出的最终起始是:gps_state-&callbacks.nmea_cb(mytimems, r-&in, r-&pos);
到这里还有个问题:GPS芯片和CPU连接,使用的是哪个串口?这个串口号怎么确定的呢?
打算贴个完整HAL层的实例,考虑到代码很多,下篇在说吧。。。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:111017次
积分:2371
积分:2371
排名:第12763名
原创:124篇
评论:24条
阅读:1271
(2)(10)(5)(2)(2)(2)(1)(4)(3)(3)(2)(2)(2)(4)(5)(2)(3)(5)(2)(2)(4)(1)(2)(4)(7)(4)(1)(4)(4)(3)(1)(9)(3)(13)(10)

我要回帖

更多关于 gps定位器 的文章

 

随机推荐