Android原生定位 Sample详情

最后更新时间:2019年6月17日

功能介绍

定位功能应用非常广泛,Google已经为Android开发者提供了原生的定位功能,开发者可直接使用Android SDK中的接口即可实现。原生定位由Android官方提供,不依赖其他任何第三方开发库。

Android原生定位提供GPS定位和网络定位两种模式。GPS定位,是通过设备中的GPS定位模块接收卫星信号,从而实现定位。Network定位(网络定位),则包括WiFi定位和基站定位两个模块:WiFi定位,是连接公共WiFi网络,可获取其固定的Mac地址,访问Google提供的定位服务查询到WiFi路由器的位置,从而获取手机的定位信息;基站定位,是在手机插入SIM卡并可用情况下,会搜索接收周围基站的信号,可利用周围三个基站的位置进行三角定位,从而获取设备的位置,或者获取基站的信息,然后访问网络,通过网络定位服务获取当前位置。两种定位模式都有各自的优缺点,在实际应用中根据需求选择。

(1)GPS定位特点:

(2)网络定位特点:

功能接口

Android原生定位提供了几个核心接口,可从Android官网提供的API中学习(网址为:https://developer.android.google.cn/reference/android/location/package-summary)。

接下来在MapGIS Mobile地图显示的基础上,详细介绍如何基于上述Android原生定位核心接口实现室外定位功能,重点讲解具体实现方法,也可查看官方API等资源深入学习。

实现步骤

接下来在MapGIS Mobile地图显示的基础上,详细介绍如何基于上述Android原生定位核心接口实现室外定位功能,重点讲解具体实现方法,也可查看官方API等资源深入学习。

1

创建工程

打开Android Studio,创建一个新工程,然后根据需求设计界面布局。

实现定位功能,要为应用配置定位权限,在AndroidManifest.xml清单文件中添加权限标签,根据需要的定位方式(GPS定位、网络定位)申请对应的权限:

<!-- 允许应用程序访问精确位置,通过GPS进行定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 允许应用程序访问近似位置,通过网络进行定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

如果设置程序的Android运行目标版本和真实运行设备的Android版本都大于6.0,则需要动态申请权限,是由于定位权限属于危险权限的范畴。

2

地图显示

采用MapGIS Mobile 10.3 for Android SDK实现地图显示,以天地图显示为例。可参考开发指南-地图SDK > 地图显示 > 在线地图显示部分文档,并可在界面中加入定位功能按钮与定位信息展示框,实现简单的展示界面。

//获取服务地图对象,其中天地图的默认地图服务类型为MapServer.MAPSERVER_TYPE_TIANDITU
MapServer mapServer = ServerLayer.createMapServer(MapServer.MAPSERVER_TYPE_TIANDITU);
//设置地图类型
mapServer.setName("Tianditu_vec");
mapServer.setAuthentication("tk", "ad6c6a0bd9b1fa421dfd77ba49e70ecf");
//设置在线url地址
mapServer.setURL("http://t0.tianditu.gov.cn/vec_c/wmts";

ServerLayer mServerLayer = new ServerLayer();
mServerLayer.setMapServer(mapServer);

//将服务图层添加到地图对象中
mMap.append(mServerLayer);

mapView.setMapAsync(mMap, new MapViewFinishCallback() {
    @Override
    public void onDidFinish(boolean success) {
        if (success) {
            //地图加载完成
        } else {
            //地图加载失败
        }
    }
});

3

获取LocationManager对象

LocationManager,定位管理器,是定位模块的核心接口。要获取定位信息,首先必须获取一个LocationManager对象,采用Context上下文的getSystemService获取实例。原生Android SDK已经提供了定位的服务。

//获取定位管理器对象
LocationManager mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

4

获取、设置标准

Criteria,用于选择位置提供者LocationProvider的应用标准的类,也即是作为定位的条件。根据实际的需求,可以对精度、海拔、方位、运营商收费、速度、电量等信息进行设置,来选择合适的定位提供者。然后调用LocationManager的getBestProvider方法获取最佳的定位提供者的名称。

Criteria criteria = new Criteria();
//设置定位精确度,Criteria.ACCURACY_FINE:较精确,Criteria.ACCURACY_COARSE:较粗略
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(true);   //设置是否需要海拔信息
criteria.setBearingRequired(true);    //设置是否需要方位信息
criteria.setCostAllowed(false);       //设置是否允许运营商收费
criteria.setSpeedRequired(true);      //设置是否需要速度信息
//设置对电量消耗的限制,POWER_LOW:低电耗;POWER_HIGH:高电耗;POWER_MEDIUM:耗电中
criteria.setPowerRequirement(Criteria.POWER_LOW);
//第一个参数:标准;第二个参数:是否只返回当前可用的定位提供者
String bestProvider=mLocationManager.getBestProvider(getCriteria(), true);

5

获取定位

获取了定位提供者之后,就可获取定位了,利用LocationManager的getLastKnownLocation获取上次定位的缓存定位位置。GPS的原理决定了首次定位会比较耗时,所以,为避免用户等待时间过长,一般在初次定位时调用此方法。

//获取最近一次定位,通过返回值Location可以获取时间、经纬度、海拔等位置信息
Location location=mLocationManager.getLastKnownLocation(bestProvider);

以上方法作用范围有限,适用在初次定位时采用,如果间隔上一次定位时间较久,得到的Location对象可能经常为Null,并且如果上一次定位在其他位置,对于此次定位也不适用。所以,还需注册定位监听,不断获取最新的位置。

调用requestLocationUpdates方法设置定位提供者、位置更新时间间隔、位置更新最小距离、定位监听器。可以设置定位方式,采用GPS定位,或者网络定位,或者使用指定的定位提供者进行定位。LocationListener是定位监听器,其中有四个回调方法,能够监听到位置提供者的开启、禁用、状态变化、定位位置变化的事件,返回信息。在位置变化回调函数中发送消息,在主线程中绘制标注、修改文本控件内容。

private LocationListener locationListener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
        //位置改变时触发
        //绘制定位点标注
        updateUIView(location);
        //获取定位点信息
        double longitude = location.getLongitude();
        double latitude = location.getLatitude();
        double altitude = location.getAltitude();
        float speed = location.getSpeed();
        float accuracy = location.getAccuracy();
        String provider = location.getProvider();
        long time = location.getTime();
        //串接为字符串
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("经度:" + longitude);
        stringBuilder.append("\n纬度:" + latitude);
        stringBuilder.append("\n高程:" + altitude);
        stringBuilder.append("\n速度:" + speed);
        stringBuilder.append("\n精度:" + accuracy);
        stringBuilder.append("\n位置提供者:" + provider);
        //时间格式转换类
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //定位完成的时间
        stringBuilder.append("\n定位时间:" + simpleDateFormat.format(time) + "\n");
        //得到定位信息字符串
        locationResult = stringBuilder.toString();
        //发送消息,在主线程修改UI
        handler.sendEmptyMessage(1);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        //位置提供者状态变化时触发,provider为位置提供者的名称,status为状态信息,extras为额外信息,例如卫星Satellites的信息
        switch (status) {
            case LocationProvider.AVAILABLE:
                Log.i(TAG, "当前位置提供者可用");
                break;
            case LocationProvider.OUT_OF_SERVICE:
                Log.i(TAG, "当前位置提供者失效,不可用");
                break;
            case LocationProvider.TEMPORARILY_UNAVAILABLE:
                Log.i(TAG, "当前位置提供者暂不可用");
                break;
            default:
                break;
        }
    }

    @Override
    public void onProviderEnabled(String provider) {
        //位置提供者开启时触发
    }

    @Override
    public void onProviderDisabled(String provider) {
        //位置提供者禁用时触发
    }
};

6

定位展示

获取到定位信息之后,可利用MapGIS Mobile提供的地图标注功能展示当前位置。

//绘制定位点标注
private void updateUIView (Location location){
    //得到定位点
    Dot locationDot = new Dot(location.getLongitude(), location.getLatitude());
    //绘制标注
    if (locationAnnotation == null) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.location1);
        locationAnnotation = new Annotation("当前位置", "位置", locationDot, bitmap);
        mapView.getAnnotationsOverlay().addAnnotation(locationAnnotation);
    } else {
        locationAnnotation.setPoint(locationDot);
    }
    mapView.zoomToCenter(locationDot, 0.00001, true);
    mapView.refresh();
}

7

GPS状态监听

如果采用GPS定位模式,可监听到GPS的状态。

//为定位管理对象添加GPS状态监听器
mLocationManager.addGpsStatusListener(listener);
/**
* GPS状态侦听器,用于GPS状态更改时接收通知
*/
GpsStatus.Listener listener = new GpsStatus.Listener() {
    @Override
    public void onGpsStatusChanged(int event) {
        switch (event) {
            //第一次定位
            case GpsStatus.GPS_EVENT_FIRST_FIX:
                Log.i(TAG, "第一次定位");
                break;
            //卫星状态改变
            case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
                Log.i(TAG, "卫星状态改变");
                //可通过更多方法获取卫星信息:如卫星颗数等
                break;
            // 定位启动
            case GpsStatus.GPS_EVENT_STARTED:
                Log.i(TAG, "定位启动");
                break;
            // 定位结束
            case GpsStatus.GPS_EVENT_STOPPED:
                Log.i(TAG, "定位结束");
                break;
        }
    }
};

8

释放监听

在不需要定位或者停止定位时,需要移除定位监听,释放资源,可在Activity的onDestroy生命周期方法中执行此操作。

@Override
protected void onDestroy () {
    super.onDestroy();
    //移除定位监听,停止更新位置
    mLocationManager.removeUpdates(locationListener);
}

9

调试运行程序

代码编写完成后,即可调试运行程序。使用USB线连接手机和电脑,然后保证设备的GPS功能和网络(包括WiFi和移动网络)开启,效果如下图所示:

GPS定位.jpg 网络定位.jpg