手机定位

来源:互联网 发布:传奇霸业血符数据 编辑:程序博客网 时间:2024/04/29 04:46
定位手机有三种定位原理,一种是GPS定位,一种是基站定位,以及两者结合的A-GPS定位。

什么是GPS定位?

  GPS定位是指手机接收GPS卫星发出信息来获得坐标经纬度确定地理位置的一种功能,GPS技术具有高精度的特点。GPS卫星定位误差值大概在5米~10米之间;  GPS定位方式可分为两部份  1、不上传定位;不上传定位指定位手机本身把接收到的GPS卫星坐标经纬度计算出的信息结果,以短信的方式通知监护人,计算结果不经过任何服务器保存;  2、上传定位;上传定位是指定位手机本身把接收到的GPS卫星坐标经纬度计算出的信息结果,以短信的方式通知监护人手机,同时上传服务器;存储到服务器后的地理位置信息由监护人保管;

什么基站定位?

  基站定位是指手机发射基站根据与手机的距离来计算手机坐标地理位置的一种功能,基站定位信号较强,适用于室内定位;基站定位误码差值大概在100米~500米之间;  基站定位方式也可分为两部份;  1、不上传定位;不上传定位是把手机基站计算距离的定位结果,以短信的方式通知监护人手机,计算结果不经过任何服务器保存;  2、上传定位;上传定位是把手机基站计算距离的定位结果,以短信的方式通知监护人手机,同时上传服务器,存储到服务器后的地理位置信息由监护人保管;  



什么是A-GPS定位?   

A-GPS是一种结合了网络基站信息和GPS信息进行定位的功能,定位手机首先采用基站定位,计算该定位手机的大概位置,然后根据该位置相关的GPS辅助信息(包含GPS的星历和方位俯仰角等),搜索GPS卫星,切换到GPS定位,一般在10秒内,就可以快速地搜星及GPS定位;



Android提供的定位接口 
在写第一个程序之前,我对android的幻想是这样的:提供了一个函数,能够让我直接从GPS模块中读取经纬度坐标,还有一个函数,能够直接访问网络,获得基站定位的结果。所以,我只需要调用调用函数就可以搞定这一切。
现实和理想总是有很大的差距。Android上的开发完全不是这么回事儿。前面提到过,GPS模块从启动到获取数据之间时间会比较长,可能有2~3分钟时间,所以,如果真有这么一个函数,那么你的程序可能会被这个函数阻塞几分钟。我想正是基于这样的考虑,android上要想获取定位信息,必须使用异步方式。

代码大概是这个样子:

view sourceprint?
01locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);  
02locListener = newLocationListener() {  
03    @Override  
04    publicvoidonStatusChanged(String provider,intstatus,  
05            Bundle extras) {  
06        // TODO Auto-generated method stub  
07    }  
08    @Override  
09    publicvoidonProviderEnabled(String provider) {  
10        // TODO Auto-generated method stub  
11    }  
12    @Override  
13    publicvoidonProviderDisabled(String provider) {  
14        // TODO Auto-generated method stub  
15    }  
16    @Override  
17    publicvoidonLocationChanged(Location location) {  
18        // TODO Auto-generated method stub  
19        mobileLocation = location;  
20    }  
21};  
22locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener);

这是从网上随便摘一段。简单解释一下代码:
首先,你需要创建一个LocationManager;
然后定义出自己的LocationListener,LocationListener包涵了好几个成员函数,它们都是回调函数。最重要的一个是“onLocationChanged”,这个函数是在android获取了新的location信息之后调用的,你可以在这个函数内来实现自己想要的功能。比如,你可以定义一个内部location变量,一旦这个函数被调用,就将内部location变量设置成最新的值;
最后,调用LocationManager.requestLocastionUpdates,它其实是将定义的locationListener注册到android中。在上面的代码中,这句话是说让LocationListener监听GPS_PROVIDER的变化。GPS_PROVIDER对应于android上的GPS模块获取位置信息,还有一个NETWORK_PROVIDER表示通过network方式获取位置信息。


问题

那么接下来就有问题了,什么时候能够真正获得手机的定位经纬度呢?等着onLocationChanged被调用吧。那它什么时候会被调用?没人知道。我写过一个小程序,测试Network方式下注册过listener之后(requestLocationUpdates函数)和onLocationChanged被调用之间的时间间隔。测试的网络条件很好。反复观察了几次,大部分都可以在几十毫秒内就返回了,但也有一些时候,时间间隔长达几十秒。这意味着,你的用户需要等上几十秒才能有返回。
所以,第一个需要注意的地方是,不要一直等待你的回调函数onLocationChanged被调用。你需要设置一个timeout机制。
这又会引入第二个问题。如果timeout了,但onLocationChanged仍然没有返回,怎么办?难道只能提示用户无法定位吗?
别急,android还提供了一个函数:getlastKnowLocation。这个函数会返回android平台最后一次获取到的位置信息。比如,你可以这样:

view plaincopy to clipboardprint?
  1. Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);  

所以,即便onLocationChanged没有被调用,我们仍然可以获取一个位置信息。当然,这里又引出了第三个问题:这个的返回值值得信赖吗?

如果用过一些LBS或者地图程序,你会发现有一个现象:在某些时候你打开地图结果被定位到的地方是你上一次使用地图程序的位置。这就是因为程序是采用getLastKnownLocation获取的位置。这个问题的解决办法是,需要定义一个标准判断获取到的Location是否可信。Android的Location这个类除了包涵有latitude,longitude,还包含有很多其他的信息,比如何时获取到的,通过哪种方式获取到的,等等。程序员完全可以基于这些信息来判断获取到的Location是否过时或者是否可信。

合理的方案

最后,说一下整体方案。Android的官方文档【1】给出了推荐的方案:

 
首先注册自己的LocationListener,让它同时监听GPS_PROVIDER和NETWORK_PROVIDER;
然后可以调用getLastKnownLocation获得一个Location值,这个值可以作为一个备选值;
然后在一段用户可接受的时间内,不断接收从onLocationChanged返回的位置,并同之前的值做比较,选取其中的最佳;
最后,会剩下一个筛选后的最优结果,你需要判断这个结果是否可接受。如果可以接受,返回给用户,如果不行,告诉用户无法定位。
整个过程你需要定义两个重要的函数:一个是比较两个Location信息,返回其中好的那个;另一个函数则用来判断Location信息是否可以被接受。


原创粉丝点击