Android原生定位服务LocationManager

目录
  • 前言
  • 一、LocationManager的使用
  • 二、混合定位
  • 总结

前言

现在的应用,几乎每一个 App 都存在定位的逻辑,方便更好的推荐产品或服务,获取当前设备的经纬度是必备的功能了。有些 App 还是以LBS(基于位置服务)为基础来实现的,比如美团,饿了吗,不获取到位置都无法使用的。

有些同学觉得不就是获取到经纬度么,Android 自带的就有位置服务 LocationManager ,我们无需引入第三方服务,就可以很方便的实现定位逻辑。

确实 LocationManager 的使用很简单,获取经纬度很方便,我们就无需第三方的服务了吗? 或者说 LocationManager 有没有坑呢?兼容性问题怎么样?获取不到位置有没有什么兜底策略?

一、LocationManager的使用

由于是Android的系统服务,直接 getSystemService 可以获取到

LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

一般获取位置有两种方式 NetWork 与 GPS 。我们可以指定方式,也可以让系统自动提供最好的方式。

// 获取所有可用的位置提供器
List<String> providerList = locationManager.getProviders(true);
// 可以指定优先GPS,再次网络定位
if (providerList.contains(LocationManager.GPS_PROVIDER)) {
    provider = LocationManager.GPS_PROVIDER;
} else if (providerList.contains(LocationManager.NETWORK_PROVIDER)) {
    provider = LocationManager.NETWORK_PROVIDER;
} else {
    // 当没有可用的位置提供器时,弹出Toast提示用户
    return;
}

当然我更推荐由系统提供,当我的设备在室内的时候就会以网络的定位提供,当设备在室外的时候就可以提供GPS定位。

 String provider = locationManager.getBestProvider(criteria, true);

我们可以实现一个定位的Service实现这个逻辑

/**
 * 获取定位服务
 */
public class LocationService extends Service {
    private LocationManager lm;
    private MyLocationListener listener;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @SuppressLint("MissingPermission")
    @Override
    public void onCreate() {
        super.onCreate();
        lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        listener = new MyLocationListener();
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_COARSE);
        criteria.setAltitudeRequired(false);//不要求海拔
        criteria.setBearingRequired(false);//不要求方位
        criteria.setCostAllowed(true);//允许有花费
        criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗
        String provider = lm.getBestProvider(criteria, true);
        YYLogUtils.w("定位的provider:" + provider);
        Location location = lm.getLastKnownLocation(provider);
        YYLogUtils.w("location-" + location);
        if (location != null) {
            //不为空,显示地理位置经纬度
            String longitude = "Longitude:" + location.getLongitude();
            String latitude = "Latitude:" + location.getLatitude();
            YYLogUtils.w("getLastKnownLocation:" + longitude + "-" + latitude);
            stopSelf();
        }
        //第二个参数是间隔时间 第三个参数是间隔多少距离,这里我试过了不同的各种组合,能获取到位置就是能,不能获取就是不能
        lm.requestLocationUpdates(provider, 3000, 10, listener);
    }
    class MyLocationListener implements LocationListener {
        // 位置改变时获取经纬度
        @Override
        public void onLocationChanged(Location location) {
            String longitude = "Longitude:" + location.getLongitude();
            String latitude = "Latitude:" + location.getLatitude();
            YYLogUtils.w("onLocationChanged:" + longitude + "-" + latitude);
            stopSelf();  // 获取到经纬度以后,停止该service
        }
        // 状态改变时
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            YYLogUtils.w("onStatusChanged - provider:"+provider +" status:"+status);
        }
        // 提供者可以使用时
        @Override
        public void onProviderEnabled(String provider) {
            YYLogUtils.w("GPS开启了");
        }
        // 提供者不可以使用时
        @Override
        public void onProviderDisabled(String provider) {
            YYLogUtils.w("GPS关闭了");
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        lm.removeUpdates(listener); // 停止所有的定位服务
    }
}

使用:定义并动态申请权限之后即可开启服务

    fun testLocation() {
        extRequestPermission(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION) {
        startService(Intent(mActivity, LocationService::class.java))
        }
    }

这样我们启动这个服务就可以获取到当前的经纬度,只是获取一次,大家如果想再后台持续定位,那么实现的方式就不同了,我们服务要设置为前台服务,并且需要额外申请后台定位权限。

话说回来,这么使用就一定能获取到经纬度吗?有没有兼容性问题

Android 5.0 Oppo

Android 6.0 Oppo海外版

Android 7.0 华为

Android 11 三星海外版

Android 12 vivo

目前测试不多,也能发现问题,特别是一些低版本,老系统的手机就可能无法获取位置,应该是系统的问题,这种服务跟网络没关系,开不开代理都是一样的。

并且随着测试系统的变高,越来越完善,提供的最好定位方式还出现混合定位 fused 的选项。

那是不是6.0的Oppo手机太老了,不支持定位了?并不是,百度定位可以获取到位置的。

既然只使用 LocationManager 有风险,有可能无法获取到位置,那怎么办?

二、混合定位

其实目前百度,高度的定位Api的服务SDK也不算大,相比地图导航等比较重的功能,定位的SDK很小了,并且目前都支持海外的定位服务。并且定位服务是免费的哦。

既然 LocationManager 有可能获取不到位置,那我们就加入第三方定位服务,比如百度定位。我们同时使用 LocationManager 和百度定位,哪个先成功就用哪一个。(如果LocationManager可用的话,它的定位比百度定位更快的)

完整代码如下:

@SuppressLint("MissingPermission")
public class LocationService extends Service {
    private LocationManager lm;
    private MyLocationListener listener;
    private LocationClient mBDLocationClient = null;
    private MyBDLocationListener mBDLocationListener;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        createNativeLocation();
        createBDLocation();
    }
    /**
     * 第三方百度定位服务
     */
    private void createBDLocation() {
        mBDLocationClient = new LocationClient(UIUtils.getContext());
        mBDLocationListener = new MyBDLocationListener();
        //声明LocationClient类
        mBDLocationClient.registerLocationListener(mBDLocationListener);
        //配置百度定位的选项
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Battery_Saving);
        option.setCoorType("WGS84");
        option.setScanSpan(10000);
        option.setIsNeedAddress(true);
        option.setOpenGps(true);
        option.SetIgnoreCacheException(false);
        option.setWifiCacheTimeOut(5 * 60 * 1000);
        option.setEnableSimulateGps(false);
        mBDLocationClient.setLocOption(option);
        //开启百度定位
        mBDLocationClient.start();
    }
    /**
     * 原生的定位服务
     */
    private void createNativeLocation() {
        lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        listener = new MyLocationListener();
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_COARSE);
        criteria.setAltitudeRequired(false);//不要求海拔
        criteria.setBearingRequired(false);//不要求方位
        criteria.setCostAllowed(true);//允许有花费
        criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗
        String provider = lm.getBestProvider(criteria, true);
        YYLogUtils.w("定位的provider:" + provider);
        Location location = lm.getLastKnownLocation(provider);
        YYLogUtils.w("location-" + location);
        if (location != null) {
            //不为空,显示地理位置经纬度
            String longitude = "Longitude:" + location.getLongitude();
            String latitude = "Latitude:" + location.getLatitude();
            YYLogUtils.w("getLastKnownLocation:" + longitude + "-" + latitude);
            stopSelf();
        }
        lm.requestLocationUpdates(provider, 3000, 10, listener);
    }
    class MyLocationListener implements LocationListener {
        // 位置改变时获取经纬度
        @Override
        public void onLocationChanged(Location location) {
            String longitude = "Longitude:" + location.getLongitude();
            String latitude = "Latitude:" + location.getLatitude();
            YYLogUtils.w("onLocationChanged:" + longitude + "-" + latitude);
            stopSelf();  // 获取到经纬度以后,停止该service
        }
        // 状态改变时
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            YYLogUtils.w("onStatusChanged - provider:" + provider + " status:" + status);
        }
        // 提供者可以使用时
        @Override
        public void onProviderEnabled(String provider) {
            YYLogUtils.w("GPS开启了");
        }
        // 提供者不可以使用时
        @Override
        public void onProviderDisabled(String provider) {
            YYLogUtils.w("GPS关闭了");
        }
    }
    /**
     * 百度定位的监听
     */
    class MyBDLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            double latitude = location.getLatitude();    //获取纬度信息
            double longitude = location.getLongitude();    //获取经度信息
            YYLogUtils.w("百度的监听 latitude:" + latitude);
            YYLogUtils.w("百度的监听 longitude:" + longitude);
            YYLogUtils.w("onBaiduLocationChanged:" + longitude + "-" + latitude);
            stopSelf();  // 获取到经纬度以后,停止该service
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 停止所有的定位服务
        lm.removeUpdates(listener);
        mBDLocationClient.stop();
        mBDLocationClient.unregisterLocationListener(mBDLocationListener);
    }
}

其实逻辑都是很简单的,并且省略了不少回调通信的逻辑,这里只涉及到定位的逻辑,别的逻辑我就尽量不涉及到。

百度定位服务的API申请与初始化请自行完善,这里只是简单的使用。并且坐标系统一为国际坐标,如果需要转gcj02的坐标系,可以网上找个工具类,或者看我之前的文章。

获取到位置之后,如何Service与Activity通信,就由大家自由发挥了,有兴趣的可以看我之前的文章。

总结

所以说Android原生定位服务 LocationManager 还是有问题啊,低版本的设备可能不行,高版本的Android系统又很行,兼容性有问题!让人又爱又恨。

很羡慕iOS的定位服务,真的好用,我们 Android 的定位服务真是拉跨,居然还有兼容性问题。

我们使用第三方定位服务和自己的 LocationManager 并发获取位置,这样可以增加容错率。是比较好用的,为什么要加上 LocationManager 呢?

我直接单独用第三方的定位服务不香吗?可以是可以,但是如果设备支持 LocationManager 的话,它会更快一点,体验更好。

以上就是Android原生定位服务LocationManager的详细内容,更多关于Android定位LocationManager的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Studio使用Profiler来完成内存泄漏的定位

    目标 使用Android Studio 4.1来完成内存泄漏的定位 目前网上大多数的文章都是在介绍Profile的使用,可以帮忙你检查出有内存泄漏,谁的内存泄漏.但是根据文章定位谁引起的这个泄漏,一直没有找到方法,通过几次努力,自己找到了比较容易的路径,希望对其他的朋友有帮助 引用 下面文章内使用的Demo在下面的地址 githubDemo 在页面内点击简单例子-> 内存泄漏-> 接着退回到上一个页面完成泄漏模拟 步骤 自己模拟一个内存泄漏 使用Profiler来完成内存泄漏的位置定位 模拟内

  • Android Location服务之LocationManager案例详解

    上次介绍了位置服务中的Geocoder,这次就来介绍一下LocationManager.LocationManager系统服务是位置服务的核心组件,它提供了一系列方法来处理与位置相关的问题,包括查询上一个已知位置.注册和注销来自某个LocationProvider的周期性的位置更新.注册和注销接近某个坐标时对一个已定义的Intent的触发等.今天我们就一起探讨一下LocationManager的简单应用. 在进入正题之前,朋友们需要了解与LocationManager相关的两个知识点: prov

  • Android 模拟地图定位功能的实现

    实现原理: 手机定位方式目前有4种: 基站定位 WIFI定位 GPS定位 AGPS定位 本工程利用手机自带的"模拟位置"功能实现运行时修改LocationManager结果. 原理:使用android自带的调试api,模拟gps provider的结果.  Android 6.0系统以下,可以通过Setting.Secure.ALLOW_MOCK_LOCATION获取是否[允许模拟位置],当[允许模拟位置]开启时,可addTestProvider:   Android 6.0系统及以上

  • Android如何实现模拟定位

    在导航测试场景中经常需要定位模拟和路线回放,记录下通过LocationManager.setTestProviderLocation()方法实现模拟地位,如果要测试的应用不支持TestProviderLocation模拟位置输入,可以考虑从HAL层入手,hook系统默认的GPS实现. 一.Android模拟权限开启配置 在Android6.0以下的版本中,需要在设置中勾选模拟定位的开关,在6.0以上就改成了选择模拟定位的应用,对应的开启配置方式也不一样,相同的是在AndroidManifest.

  • 一分钟快速定位Android启动耗时问题

    目录 前言 1. 接入Tencent Matrix 2. 改造Application子类 3.运行,快速定位 总结 前言 Tencent Matrix默认无法监测Application冷启动的耗时方法,本文介绍了如何改造Matrix支持冷启动耗时方法监测.让你一分钟就能给App启动卡顿号脉. 1. 接入Tencent Matrix 1.1 在你项目根目录下的 gradle.properties 中配置要依赖的 Matrix 版本号,如: MATRIX_VERSION=1.0.0 1.2 在你项目

  • 解决Android原生定位的坑

    Android原生定位的代码网上已经很多了,就不贴出来. 简单了解下: GPS_PROVIDER:通过手机内置的GPS芯片,利用卫星获取定位信息.位置监听.卫星状态监听很耗电且室内定位很不准确. NETWORK_PROVIDER:网络定位通过基站和WiFi节点,利用节点id在定位数据服务器查询位置信息.但是国内网络不允许,且有消息称Google已不提供该服务.so网上出现的此种方式获取定位信息不可用,也就是说NETWORK_PROVIDER在国内不可用. PASSIVE_PROVIDER:被动定

  • Android LocationManager获取经度与纬度等地理信息

    Android LocationManager获取经度与纬度等地理信息 利用LocationManager实现定位功能 1 实时更新经度,纬度 2 根据经度和纬度获取地理信息(比如:国家,街道等)(略过) MainActivity如下: package cc.bb; import java.util.Iterator; import java.util.List; import android.location.Location; import android.location.Location

  • Android原生定位服务LocationManager

    目录 前言 一.LocationManager的使用 二.混合定位 总结 前言 现在的应用,几乎每一个 App 都存在定位的逻辑,方便更好的推荐产品或服务,获取当前设备的经纬度是必备的功能了.有些 App 还是以LBS(基于位置服务)为基础来实现的,比如美团,饿了吗,不获取到位置都无法使用的. 有些同学觉得不就是获取到经纬度么,Android 自带的就有位置服务 LocationManager ,我们无需引入第三方服务,就可以很方便的实现定位逻辑. 确实 LocationManager 的使用很

  • Android GPS定位测试(附效果图和示例)

    今天因为工作需要,把以前编写的一个GPS测试程序拿出来重新修改了一下.这个程序说起来有些历史了,是我11年编写的,那时候学了Android开发没多久,算是一个实验性的作品.现在工作需要,重新拿出来修整.同时发现我对android的GPS服务了解并不深,所以今天特意阅读了有关GPS服务的一些资料,把相关知识点记录下来. 本人做了GPS相关的嵌入式软件已经几年了,所以说起要做个测试GPS定位模块的程序,第一反应就是串口读取GPS模块的数据,然后解析GPS的NMEA格式数据.NMEA是一种标准化数据格

  • Android开发之android_gps定位服务简单实现

    前言 gps定位服务的学习是这段时间gps课程的学习内容,之前老师一直在将概念,今天终于是实践课(其实就是给了一个案例,让自己照着敲).不过在照着案列敲了两遍之后,发现老师的案例是在是太老了,并且直接照着案例敲,也无法理解其中很多类,方法的作用. 于是自己在网上查看了其他实现的方法,并尝试敲案列,期间的挫折一言难尽. (网上找的案例也并不信息,使得我在给予权限,和权限检查方面一直报错,因为我使用的是最新的As和java11,在经过数遍从基础理解到实例编写的过程和不知多少遍google之后,终于完

  • Android GPS定位详解及实例代码

    GPS定位是智能手机上一个比较有意思的功能,LBS等服务都有效的利用了GPS定位功能.本文就跟大家分享下Android开发中的GPS定位知识.      一.Android基础知识准备 1.Activity类 每一种移动开发环境都有自己的基类.如J2ME应用程序的基类是midlets,BREW的基类是applets,而Android程序的基类是Activity.这个activity为我们提供了对移动操作系统的基本功能和事件的访问.这个类包含了基本的构造方法,键盘处理,挂起来恢复功能,以及其他底层

  • Android判断定位功能是否可用的方法

    定位功能是否可用由定位服务和定位权限共同决定: 判断定位服务: /** * 手机是否开启位置服务,如果没有开启那么所有app将不能使用定位功能 */ public static boolean isLocServiceEnable(Context context) { LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); boolean gps

  • Android原生嵌入React Native详解

    1.首先集成的项目目录 我使用的是直接按照react-native init Project 的格式来导入的,也就是说,我的Android项目目录是跟node_modules是在一个目录下的. 我们init完项目之后,项目初始化完成了,这时候我们可以用命令react-native run-android直接运行项目,至于怎么调试,之前已经说过. 说一下我们怎么开发和运行分开吧,我们开发一般会选择webstrom,开发后我们会Android和ios的编译分开. 启动npm 下面说一下android

  • Android百度定位导航之基于百度地图移动获取位置和自动定位

    一.问题描述 使用百度地图实现如图所示应用,首先自动定位当前我起始位置(小圆点位置),并跟随移动不断自动定位我的当前位置 百度Api不同版本使用会有些差异,本例中加入lib如下: 二.编写MyApplication类 public class MyApplication extends Application { static MyApplication myApplication; BMapManager mBMapManager = null; String mStrKey = "7ZfuR

  • Android中Service服务详解(一)

    本文详细分析了Android中Service服务.分享给大家供大家参考,具体如下: 一.Service简介 Service是Android中实现程序后台运行的解决方案,适用于去执行那些不需要和用户交互而且还要求长期运行的任务.Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver.ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互. Service并不是运行

随机推荐