做移动互联网就不太可能不碰手机端的开发。上周为了项目需要,俺也挽袖子抡胳膊开始写起了android程序,还好有java基础,倒也上手快,写了几个小程序,主要都是关于定位方面的。
网上也搜得到一些相关的文章和教程,但给出的例子效果不太好,而且感觉只有其表,却不明其理。因此写出此文,分享一些我的经验。虽然是以android为主,但是我想对其它平台的开发也应该有些帮助。

这篇文章侧重于制定一个合理的定位方案。

手机定位的方式 
先科普一些基础知识吧。

最简单的手机定位方式当然是通过GPS模块(现在大部分的智能机应该都有了)。GPS方式准确度是最高的,但是它的缺点也非常明显:1,比较耗电;2,绝大部分用户默认不开启GPS模块;3,从GPS模块启动到获取第一次定位数据,可能需要比较长的时间;4,室内几乎无法使用。这其中,缺点2,3都是比较致命的。需要指出的是,GPS走的是卫星通信的通道,在没有网络连接的情况下也能用。
另外一种常见的定位方式是基站定位。大致思路就是采集到手机上的基站ID号(cellid)和其它的一些信息(MNC,MCC,LAC等等),然后通过网络访问一些定位服务,获取并返回对应的经纬度坐标。基站定位的精确度不如GPS,但好处是能够在室内用,只要网络通畅就行。
还有Wifi定位。和基站定位类似,这种方式是通过获取当前所用的wifi的一些信息,然后访问网络上的定位服务以获得经纬度坐标。因为它和基站定位其实都需要使用网络,所以在Android也统称为Network方式。
最后需要解释一点的是AGPS方式。很多人将它和基站定位混为一谈,但其实AGPS的本质仍然是GPS,只是它会使用基站信息对获取GPS进行辅助,然后还能对获取到的GPS结果进行修正,所以AGPS要比传统的GPS更快,准确度略高。

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

代码大概是这个样子:

01 locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);  
02 locListener = 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 };  
22 locManager.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平台最后一次获取到的位置信息。比如,你可以这样:

  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信息是否可以被接受。

android定位方式的更多相关文章

  1. 六 APPIUM Android 定位方式

    文本转自:http://www.cnblogs.com/sundalian/p/5629500.html APPIUM Android 定位方式   1.定位元素应用元素 1.1通过id定位元素 An ...

  2. Android定位方式和测试方法

    Android常用的三种定位方式有:基于GPS定位.基于基站地位.基于wifi定位. 1.基于GPS定位: GPS定位需要GPS模块(硬件)的支持,没有GPS模块是无法进行GPS定位的. GPS定位最 ...

  3. 七 APPIUM Android 定位方式

    1.定位元素应用元素   1.1通过id定位元素 Android里面定位的id一般为resrouce-id: 代码可以这样写: WebElement element = driver.findElem ...

  4. APPIUM Android 定位方式

    原文地址https://www.cnblogs.com/sundalian/p/5629500.html 1.定位元素应用元素 1.1通过id定位元素 Android里面定位的id一般为resrouc ...

  5. Android定位测试(深坑)

    问题:我们是一个海外app,市场部去马来西亚打开那边的市场,发现了一个问题,就是我们的app定位有问题,还是成都的定位,主要原因是在马来西亚使用这个app,请求中带的经纬度参数是成都的,导致服务器返回 ...

  6. android 定位的四种方式

    [原文]  开发中对于地图及地理位置的定位是我们经常要用地,地图功能的使用使得我们应用功能更加完善,下面总结了一下网络中现有对于介绍android定位的4种方式,希望对大家有帮助: android 定 ...

  7. android 三种定位方式

    http://www.cnblogs.com/oudi/archive/2012/03/22/2411509.html 最近在看android关于定位的方式,查了很多资料,也做了相关实验,在手机上做了 ...

  8. android 定位的几种方式介绍

    [地理位置] android 定位的几种方式介绍 开发中对于地图及地理位置的定位是我们经常要用地,地图功能的使用使得我们应用功能更加完善,下面 www.androidkaifa.com 总结了一下网络 ...

  9. 技术分享 | app自动化测试(Android)--元素定位方式与隐式等待

    原文链接 元素定位是 UI 自动化测试中最关键的一步,假如没有定位到元素,也就无法完成对页面的操作.那么在页面中如何定位到想要的元素,本小节讨论 Appium 元素定位方式. Appium的元素定位方 ...

随机推荐

  1. 自己定义android 4.0以上的对话框风格

    做个笔记.这里是Dialog的风格,假设是用AlertDialog创建的,不能直接用.在styles.xml的写法: <style name="DialogWindowTitle&qu ...

  2. SystemParametersInfo API学习(128个中文参数解释,215个实际值)

    uiAction:该参数指定要查询或设置的系统级参数.其取值如下:SPI_GETACCESSTIMEOUT:检索与可访问特性相关联的超时段的信息,PvParam参数必须指向某个ACCESSTIMEOU ...

  3. c/c++数组名和指针区别深入探索

    指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用.于是乎,很多程序设计者就被搞糊涂了.而许多的大学老师,他们在C语言的教学过程中也错误得给学生讲解:&quo ...

  4. centos7里默认python升级到2.7.11

    CentOS镜像使用帮助 http://mirrors.163.com/.help/centos.html   安装gcc yum install gcc* openssl openssl-devel ...

  5. 如何得到动态链接库的输出函数tdump命令(225篇博文)

    有的时候,我们需要查看一个动态链接库的输出函数列表,有很多软件可以满足此要求,比如说 exeScope.不过,去下载一个软件总归是很麻烦,Delphi 本身就自带一个类似的工具,那就是 tdump.e ...

  6. [c++语法]类

    什么是类 类 是 面向对象的基础.c里面是没有对象的,只有数据,即静态的死物. 从面向过程升级到面向对象后,有了对象的概念,对象是数据与方法的合体,是动态的活物. 类代表着一类事物的特征.而对象,是类 ...

  7. jquery实现菜单功能(单击展开或者关闭)-一般应用于后台

    <!doctype html> <html> <head> <meta charset="gb2312"> <title> ...

  8. hdu3068之manacher算法+详解

    最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  9. Mars之android的Handler(2)

    handler .looper.messageque的关系在前面已经有个介绍,但前面handler(1)中handler的使用是极少的一种情况,因为handler.sendMessage()可以在Ma ...

  10. hdu2151(递推dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2151 分析: DP.思路:全盘扫描.     i表示时间,l表示第几棵树,方程:     step[i ...