Android实现定位的解决方案

avatar
avatar
kktoo
45
文章
12
评论
2021年2月1日17:04:02 评论 3,967 3731字阅读12分26秒

1 前言

相当数量的app应用和游戏,都需要用到定位功能。主要有两类实现思路:一是使用Android自带的位置服务;二是接入第三方SDK,常见的有百度地图,高德地图,腾讯地图等等;

开门见山,先说结论: 在大陆上线运营的中小开发者,不要考虑Android自带的定位,这是个浪费时间的死胡同。接入第三方SDK,免费、简单、可以快速投入使用。

有想了解详细原因的看官,剖析如下:

2 Android自带位置服务

LocationManager系统服务是位置服务的核心组件,它提供了一系列方法来处理与位置相关的问题,比如查询上一个已知位置,定期更新设备的地理位置,或者当设备进入给定地理位置附近时,触发应用指定意图等;

2.1 获取LocationManager:

mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 

2.2 了解LocationProvider:

LocationProvider:它是位置信息提供者,系统提供三种方式获取地理位置信息:

(1)GPS_PROVIDER: 通过 GPS芯片利用卫星来获取地理位置信息; 优点:获取地理位置信息精确度高; 缺点:只能在户外使用,获取经纬度信息耗时,耗电;

(2)NETWORK_PROVIDER: 通过移动网络的基站和Wi-Fi节点的地址来获取地理位置;这种方式依赖于将基站或WIF节点信息翻译成位置信息的服务器的能力。 通过我们到附近3个不同基站的距离,就可以确定我们的坐标,这个是数学中三位定点的原理。 优点:只要有网络,就可以快速定位,室内室外都可; 缺点:精确度不高;

(3)PASSIVE_PROVIDER: 被动接收更新地理位置信息,而不用自己请求地理位置信息。意思就是捡现成的,当其他应用使用定位更新了定位信息,系统会保存下来,当前应用被动接收到定位信息后直接读取就可以了。 换而言之,此方法依赖于其他Provider,不能独立存在;

2.3 获取LocationProvider:

(1)getProvider(指定获取某个Provider)

String provider = mLocationManager.getProvider(LocationManager.GPS_PROVIDER);

(2)getProviders(获取所有Provider)

List<String> list = locationManager.getProviders(true);
            if (list.contains(LocationManager.GPS_PROVIDER)) {
                Log.i(TAG, "为GPS位置控制器");
            } else if (list.contains(LocationManager.NETWORK_PROVIDER)) {
                Log.i(TAG, "为网络位置控制器");
            } else if (list.contains(LocationManager.PASSIVE_PROVIDER)) {
                Log.i(TAG, "为被动位置控制器");
            } else {
                Log.i(TAG, "其他");
            }

(3)getBestProvider(根据一组条件来返回合适的Provider)

            Criteria c = new Criteria();//Criteria类是设置定位的标准信息(系统会根据你的要求,匹配最适合你的定位供应商),一个定位的辅助信息的类
            c.setPowerRequirement(Criteria.POWER_LOW);//设置低耗电
            c.setAltitudeRequired(true);//设置需要海拔
            c.setBearingAccuracy(Criteria.ACCURACY_LOW);//设置COARSE精度标准
            c.setAccuracy(Criteria.ACCURACY_FINE);//设置低精度
            //... Criteria 还有其他属性,就不一一介绍了
            String provider = locationManager.getBestProvider(c, false);
            if (TextUtils.isEmpty(provider)) {
                Log.i(TAG, "找不到最适合的定位");
            }else{
                Log.i(TAG, "找到最适合的定位");
            }

2.4 监听

LocationListener locationListener = new LocationListener() {
        @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) {
            longitude = location.getLongitude();
            latitude  = location.getLatitude();
            Log.d(TAG,"Location longitude:"+ longitude +" latitude: "+ latitude );
        }
};

2.5 获取位置

Location location = mLocationManager.getLastKnownLocation(serviceProvider);

或者

Location location = mLocationManager.getLocation(serviceProvider);  

2.6 请求更新位置

mLocationManager.requestLocationUpdates(serviceProvider, 10000, 1, locationListener);

3 使用自带定位服务会遇到的问题举例:

常见问题1 LocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)返回结果恒为false

原因分析: 大陆绝大多数手机厂商制造的手机,由于政策限制,有所裁剪,比如裁剪了一些google服务,所以官方的location manager库缺少network组件,大陆网络也不允许有服务器来做这个事情,所以总是返回false。

常见问题2 getLocation返回的location永远为NULL

网上有解决方案说,一开始location是很有可能是NULL的,这是因为程序还从来没有请求 过,只需要注册监听器,然后固定时间间隔一直请求更新location,就可以在onLocationChanged中接收更新后的location信息。其实也是走不通的,你会发现永远不会进入onLocationChanged。

原因分析: 这种情况都是发生在室内,因为GPS无法获取位置,而由于问题1的原因,NETWORK_PROVIDER无法正常工作,所以是获取不到位置的,只有一直返回NULL。

常见问题3 requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 1, locationListener); 永远失败。

在室内, requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 1, locationListener); 永远失败。

而换成requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 1, locationListener); 则可以成功。

这是因为GPS_PROVIDER在室内是无法定位的,在室外才能定位,在室内只能依赖NETWORK_PROVIDER。

这其实是个很多人都知道的常识,但是在办公室里做开发的时候,往往没有反应过来。

4 做出选择

综上所述,如果我们要使用安卓自带的位置服务,则必须接受:

1 要求用户必须打开GPS信号开关;

GPS信号比较耗电,用户也懒的操作打开GPS,又操作授权定位权限。

2 室内定位不准;

相信大多数用户在室内的时间都比在室外的时间长。

3 定位sdk目前多数有免费政策;

百度地图:http://lbsyun.baidu.com/products/location

高德地图:https://developer.amap.com/product/locate

腾讯地图:https://lbs.qq.com/location/

附:上述结论只适用于目前的国内市场,不契合海外市场的情况。

avatar
  • 文本由 发表于 2021年2月1日17:04:02
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
Unity接入安卓SDK(3)厘清Gradle的版本 Android

Unity接入安卓SDK(3)厘清Gradle的版本

接入过程中,很多人遇到gradle的各种错误,由于对各种gradle版本的概念不甚了了,模模糊糊一顿操作猛如虎,糊弄的能编译通过就万事大吉,下次再遇到又是一脸懵逼。所以我们还是一起先厘清gradle的...
华为渠道接入的小细节 Android

华为渠道接入的小细节

一、集成HMS SDK 3.0报错AGConnectInitializeProvider 现象: 华为渠道接入使用的maven仓,兴冲冲配置完毕之后,一运行就crash了,真扫兴,查看logcat: ...
windows下配置Ninja Android

windows下配置Ninja

描述: mac上的android工程,改为在windows下继续开发。报错: CMake Error: CMake was unable to find a build program corresp...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: