在Android开发其中。常常须要用到定位功能,尤其是依赖于地理位置功能的应用。非常多人喜欢使用百度地图,高德地图提供的sdk。开放API,可是在只须要经纬度,或者城市,街道地址等信息。并不须要提供预览地图,地图界面的应用中。这时,不须要使用百度地图。高德地图。这样做只会添加apk的体积。怎么办呢?

事实上LocationManager,Geocoder这些Android API给我们提供的这些类就能够满足了。

以下笔者就来讲讲怎样利用LocationManager获取经纬度,并利用Geocoder将经纬度转换为城市街道等信息。

添加权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

LocationManager定位管理者实例通过getSystemService()方式获得:

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

定位大致分为三大类:GPS定位;Network定位;AGPS定位。
而Network又细分为WIFI定位和基站定位。下面详细讲解每种定位:

  
GPS定位:需要GPS硬件支持,直接和卫星交互来获取当前经纬度。

优点:速度快、精度高、可在无网络情况下使用。

缺点:首次连接时间长、只能在户外已经开阔地使用,设备上方有遮挡物就不行了、比较耗电。

代码:

/*** GPS定位*/
public class GpsLocationActivity extends AppCompatActivity implements PermissionUtils.PermissionCallbacks {private LocationManager mLocationManager;private String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION};private static final int REQUEST_PERMISSION_CODE = 12;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_gps_location);}public void doClick(View view) {if (!PermissionUtils.hasPermissions(this, permissions)) {PermissionUtils.requestPermissions(this, REQUEST_PERMISSION_CODE, permissions);} else {startLocate();}}private void startLocate() {mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);boolean providerEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);if (providerEnabled) { //GPS已开启/*** 绑定监听* 参数1,设备:有GPS_PROVIDER和NETWORK_PROVIDER两种,前者是GPS,后者是GPRS以及WIFI定位* 参数2,位置信息更新周期.单位是毫秒* 参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息* 参数4,监听* 备注:参数2和3,如果参数3不为0,则以参数3为准;参数3为0,则通过时间来定时更新;两者为0,则随时刷新*/mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);} else {Toast.makeText(this, "请打开GPS", Toast.LENGTH_SHORT).show();}}private LocationListener locationListener = new LocationListener() {@Overridepublic void onLocationChanged(Location location) {//位置信息变化时触发Log.e("xyh", "定位方式:" + location.getProvider());Log.e("xyh", "纬度:" + location.getLatitude());Log.e("xyh", "经度:" + location.getLongitude());Log.e("xyh", "海拔:" + location.getAltitude());Log.e("xyh", "时间:" + location.getTime());}@Overridepublic void onStatusChanged(String provider, int status, Bundle extras) {//GPS状态变化时触发switch (status) {case LocationProvider.AVAILABLE:Log.e("onStatusChanged", "当前GPS状态为可见状态");break;case LocationProvider.OUT_OF_SERVICE:Log.e("onStatusChanged", "当前GPS状态为服务区外状态");break;case LocationProvider.TEMPORARILY_UNAVAILABLE:Log.e("onStatusChanged", "当前GPS状态为暂停服务状态");break;}}@Overridepublic void onProviderEnabled(String provider) {//GPS开启时触发Log.e("xyh", "onProviderEnabled: ");}@Overridepublic void onProviderDisabled(String provider) {//GPS禁用时触发Log.e("xyh", "onProviderDisabled: ");}};@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);PermissionUtils.onRequestPermissionsResult(requestCode, permissions, grantResults, this);}@Overridepublic void onPermissionsAllGranted(int requestCode, List<String> perms, boolean isAllGranted) {if (isAllGranted) {startLocate();}}@Overridepublic void onPermissionsDenied(int requestCode, List<String> perms) {if (PermissionUtils.somePermissionPermanentlyDenied(this, perms)) {PermissionUtils.showDialogGoToAppSettting(this);} else {PermissionUtils.showPermissionReason(requestCode, this, permissions, "需要定位权限");}}
}

定位结果:

08-22 15:34:48.002 10039-10039/com.xiaoyehai.locationmanager E/xyh: 定位方式:gps
08-22 15:34:48.002 10039-10039/com.xiaoyehai.locationmanager E/xyh: 纬度:23.16859603
08-22 15:34:48.002 10039-10039/com.xiaoyehai.locationmanager E/xyh: 经度:113.34331354
08-22 15:34:48.002 10039-10039/com.xiaoyehai.locationmanager E/xyh: 海拔:77.0
08-22 15:34:48.002 10039-10039/com.xiaoyehai.locationmanager E/xyh: 时间:1534923287000

网络定位:

优点:它的优势在于收环境影响较小

缺点: 首先需要消耗流量、其实精度没有GPS那么准确,大概在十几米到几十米之间。

定位工具类:LocationUtils

/*** 定位工具类* Created by xiaoyehai on 2018/8/22 0022.*/public class LocationUtils {private static OnLocationChangeListener mListener;private static MyLocationListener myLocationListener;private static LocationManager mLocationManager;private LocationUtils() {throw new UnsupportedOperationException("u can't instantiate me...");}/*** 判断Gps是否可用** @return {@code true}: 是<br>{@code false}: 否*/public static boolean isGpsEnabled(Context context) {LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}/*** 判断定位是否可用** @return {@code true}: 是<br>{@code false}: 否*/public static boolean isLocationEnabled(Context context) {LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);return lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) || lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}/*** 打开Gps设置界面*/public static void openGpsSettings(Context context) {Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent);}/*** 注册* <p>使用完记得调用{@link #unregister()}</p>* <p>需添加权限 {@code <uses-permission android:name="android.permission.INTERNET"/>}</p>* <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>}</p>* <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>}</p>* <p>如果{@code minDistance}为0,则通过{@code minTime}来定时更新;</p>* <p>{@code minDistance}不为0,则以{@code minDistance}为准;</p>* <p>两者都为0,则随时刷新。</p>** @param minTime     位置信息更新周期(单位:毫秒)* @param minDistance 位置变化最小距离:当位置距离变化超过此值时,将更新位置信息(单位:米)* @param listener    位置刷新的回调接口* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败*/public static boolean register(Context context, long minTime, long minDistance, OnLocationChangeListener listener) {if (listener == null)return false;mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);mListener = listener;if (!isLocationEnabled(context)) {Toast.makeText(context, "无法定位,请打开定位服务", Toast.LENGTH_SHORT).show();return false;}String provider = mLocationManager.getBestProvider(getCriteria(), true);Location location = mLocationManager.getLastKnownLocation(provider);if (location != null)listener.getLastKnownLocation(location);if (myLocationListener == null)myLocationListener = new MyLocationListener();mLocationManager.requestLocationUpdates(provider, minTime, minDistance, myLocationListener);return true;}/*** 注销*/public static void unregister() {if (mLocationManager != null) {if (myLocationListener != null) {mLocationManager.removeUpdates(myLocationListener);myLocationListener = null;}mLocationManager = null;}}/*** 设置定位参数** @return {@link Criteria}*/private static Criteria getCriteria() {Criteria criteria = new Criteria();//设置定位精确度 Criteria.ACCURACY_COARSE比较粗略,Criteria.ACCURACY_FINE则比较精细criteria.setAccuracy(Criteria.ACCURACY_FINE);//设置是否要求速度criteria.setSpeedRequired(false);// 设置是否允许运营商收费criteria.setCostAllowed(false);//设置是否需要方位信息criteria.setBearingRequired(false);//设置是否需要海拔信息criteria.setAltitudeRequired(false);// 设置对电源的需求criteria.setPowerRequirement(Criteria.POWER_LOW);return criteria;}/*** 根据经纬度获取地理位置** @param context   上下文* @param latitude  纬度* @param longitude 经度* @return {@link Address}*/public static Address getAddress(Context context, double latitude, double longitude) {Geocoder geocoder = new Geocoder(context, Locale.getDefault());try {List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);if (addresses.size() > 0)return addresses.get(0);} catch (IOException e) {e.printStackTrace();}return null;}/*** 根据经纬度获取所在国家** @param context   上下文* @param latitude  纬度* @param longitude 经度* @return 所在国家*/public static String getCountryName(Context context, double latitude, double longitude) {Address address = getAddress(context, latitude, longitude);return address == null ? "unknown" : address.getCountryName();}/*** 根据经纬度获取所在地** @param context   上下文* @param latitude  纬度* @param longitude 经度* @return 所在地*/public static String getLocality(Context context, double latitude, double longitude) {Address address = getAddress(context, latitude, longitude);return address == null ? "unknown" : address.getLocality();}/*** 根据经纬度获取所在街道** @param context   上下文* @param latitude  纬度* @param longitude 经度* @return 所在街道*/public static String getStreet(Context context, double latitude, double longitude) {Address address = getAddress(context, latitude, longitude);return address == null ? "unknown" : address.getAddressLine(0);}private static class MyLocationListener implements LocationListener {/*** 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发** @param location 坐标*/@Overridepublic void onLocationChanged(Location location) {if (mListener != null) {mListener.onLocationChanged(location);}}/*** provider的在可用、暂时不可用和无服务三个状态直接切换时触发此函数** @param provider 提供者* @param status   状态* @param extras   provider可选包*/@Overridepublic void onStatusChanged(String provider, int status, Bundle extras) {if (mListener != null) {mListener.onStatusChanged(provider, status, extras);}switch (status) {case LocationProvider.AVAILABLE:Log.e("onStatusChanged", "当前GPS状态为可见状态");break;case LocationProvider.OUT_OF_SERVICE:Log.e("onStatusChanged", "当前GPS状态为服务区外状态");break;case LocationProvider.TEMPORARILY_UNAVAILABLE:Log.e("onStatusChanged", "当前GPS状态为暂停服务状态");break;}}/*** provider被enable时触发此函数,比如GPS被打开*/@Overridepublic void onProviderEnabled(String provider) {}/*** provider被disable时触发此函数,比如GPS被关闭*/@Overridepublic void onProviderDisabled(String provider) {}}public interface OnLocationChangeListener {/*** 获取最后一次保留的坐标** @param location 坐标*/void getLastKnownLocation(Location location);/*** 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发** @param location 坐标*/void onLocationChanged(Location location);/*** provider的在可用、暂时不可用和无服务三个状态直接切换时触发此函数** @param provider 提供者* @param status   状态* @param extras   provider可选包*/void onStatusChanged(String provider, int status, Bundle extras);//位置状态发生改变}
}

使用:

   public void doClick(View view) {LocationUtils.register(this, 0, 0, new LocationUtils.OnLocationChangeListener() {@Overridepublic void getLastKnownLocation(Location location) {Log.e("xyh", "onLocationChanged: " + location.getLatitude());}@Overridepublic void onLocationChanged(Location location) {//位置信息变化时触发Log.e("xyh", "定位方式:" + location.getProvider());Log.e("xyh", "纬度:" + location.getLatitude());Log.e("xyh", "经度:" + location.getLongitude());Log.e("xyh", "海拔:" + location.getAltitude());Log.e("xyh", "时间:" + location.getTime());Log.e("xyh", "国家:" + LocationUtils.getCountryName(NetWorKLocationActivity.this, location.getLatitude(), location.getLongitude()));Log.e("xyh", "获取地理位置:" + LocationUtils.getAddress(NetWorKLocationActivity.this, location.getLatitude(), location.getLongitude()));Log.e("xyh", "所在地:" + LocationUtils.getLocality(NetWorKLocationActivity.this, location.getLatitude(), location.getLongitude()));Log.e("xyh", "所在街道:" + LocationUtils.getStreet(NetWorKLocationActivity.this, location.getLatitude(), location.getLongitude()));}@Overridepublic void onStatusChanged(String provider, int status, Bundle extras) {}});}@Overrideprotected void onDestroy() {super.onDestroy();LocationUtils.unregister();}
}

定位结果:

08-22 15:43:47.445 11529-11529/com.xiaoyehai.locationmanager E/xyh: 定位方式:network
08-22 15:43:47.445 11529-11529/com.xiaoyehai.locationmanager E/xyh: 纬度:23.168848
08-22 15:43:47.445 11529-11529/com.xiaoyehai.locationmanager E/xyh: 经度:113.343307
08-22 15:43:47.445 11529-11529/com.xiaoyehai.locationmanager E/xyh: 海拔:0.0
08-22 15:43:47.446 11529-11529/com.xiaoyehai.locationmanager E/xyh: 时间:1534923825508
08-22 15:43:47.847 11529-11529/com.xiaoyehai.locationmanager E/xyh: 国家:中国
08-22 15:43:48.182 11529-11529/com.xiaoyehai.locationmanager E/xyh: 获取地理位置:Address[addressLines=[0:"广东省广州市天河区xxx219",1:"广州市轻工职业学校",2:"长兴智汇商务中心-G座",3:"xx大厦",4:"广州天河软件园(智汇分园)",5:"长福路小区",6:"广州华南商贸职业学院",7:"长兴·智汇商务中心",8:"永佳连锁超市(广州)",9:"广州市创艺艺术职业学校",10:"广州嘉福利晶酒店(天河店)"],feature=null,admin=广东省,sub-admin=null,locality=广州市,thoroughfare=长福路,postalCode=null,countryCode=0,countryName=中国,hasLatitude=true,latitude=23.172007566919543,hasLongitude=true,longitude=113.35534387635434,phone=null,url=null,extras=null]
08-22 15:43:48.580 11529-11529/com.xiaoyehai.locationmanager E/xyh: 所在地:广州市
08-22 15:43:48.844 11529-11529/com.xiaoyehai.locationmanager E/xyh: 所在街道:广东省广州市天河区XX路258741

PermissionUtils:

/*** 动态申请权限工具类* Created by xiaoyehai on 2018/4/25 0025.*/public class PermissionUtils {public static final int GOTO_SEETING_CODE = 152;/*** 判断是否有权限** @param context* @param perms* @return*/public static boolean hasPermissions(@NonNull Context context, @Size(min = 1) @NonNull String... perms) {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {return true;}if (context == null) {throw new IllegalArgumentException("Can't check permissions for null context");}for (String perm : perms) {if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) {return false;}}return true;}/*** 申请权限*/public static void requestPermissions(@NonNull Activity activity, int requestCode, String[] permissions) {List<String> permissionList = new ArrayList<>();for (String permission : permissions) {if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {permissionList.add(permission);}}String[] permissionsArray = permissionList.toArray(new String[permissionList.size()]);//将List转为数组if (permissionList.isEmpty()) {//不可能为空} else {ActivityCompat.requestPermissions(activity, permissionsArray, requestCode);//返回结果onRequestPermissionsResult}}/*** 申请权限的回调** @param requestCode  请求权限时传入的请求码,用于区别是哪一次请求的* @param permissions  所请求的所有权限的数组* @param grantResults 权限授予结果,和 permissions 数组参数中的权限一一对应,元素值为两种情况,如下:*                     授予: PackageManager.PERMISSION_GRANTED*                     拒绝: PackageManager.PERMISSION_DENIED*/public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults, @NonNull PermissionCallbacks callBack) {//授予的权限。List<String> granted = new ArrayList<>();//拒绝的权限List<String> denied = new ArrayList<>();for (int i = 0; i < permissions.length; i++) {String perm = permissions[i];if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {granted.add(perm);} else {denied.add(perm);}}if (null != callBack) {if (denied.isEmpty()) {callBack.onPermissionsAllGranted(requestCode, granted, denied.isEmpty());}if (!denied.isEmpty()) {callBack.onPermissionsDenied(requestCode, denied);}}}/*** 用户是否拒绝权限,并检查“不要提醒”。** @param activity* @param perms* @return*/public static boolean somePermissionPermanentlyDenied(Activity activity, @NonNull List<String> perms) {for (String deniedPermission : perms) {if (permissionPermanentlyDenied(activity, deniedPermission)) {return true;}}return false;}public static boolean permissionPermanentlyDenied(Activity activity, @NonNull String perms) {if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, perms)) {return true;}return false;}public static void showDialogGoToAppSettting(final Activity activity) {AlertDialog dialog = new AlertDialog.Builder(activity).setMessage("去设置界面开启权限").setPositiveButton("确定", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {// 跳转到应用设置界面goToAppSetting(activity);}}).setCancelable(false).show();}/*** 跳转到应用设置界面*/public static void goToAppSetting(Activity activity) {Intent intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);Uri uri = Uri.fromParts("package", activity.getPackageName(), null);intent.setData(uri);activity.startActivityForResult(intent, GOTO_SEETING_CODE);}public static void showPermissionReason(final int requestCode, final Activity activity, final String[] permission, String s) {AlertDialog dialog = new AlertDialog.Builder(activity).setMessage(s).setPositiveButton("确定", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {requestPermissions(activity, requestCode, permission);}}).setCancelable(false).show();}public interface PermissionCallbacks {/*** @param isAllGranted 是否全部同意*/void onPermissionsAllGranted(int requestCode, List<String> perms, boolean isAllGranted);/***/void onPermissionsDenied(int requestCode, List<String> perms);}
}

android 定位功能的实现相关推荐

  1. 基于百度地图实现Android定位功能实现(详解+教程)

    基于百度地图实现Android定位功能实现(详解+教程) 1.初始化 (一)获取到SHA1 (1)找到View中的Tool Windows并打开Terminal (2)找到你的jdk的bin目录,小编 ...

  2. Android定位功能(二)

    在前文Android定位功能(一)中,已经大致介绍了一下在Android平台中,和定位功能相关的类,并举例获取了位置信息.但是前文是基于Criteria定制了一个标准,通过getBestProvide ...

  3. 基于百度地图实现Android定位功能实现

    基于百度地图实现Android定位功能实现 初始化 一>获取SHA1 二>Android studio 配置 (1)下载百度地图sdk (2)解压安装包 (3)回到刚刚配置的jar包,右击 ...

  4. Android 定位功能简单实现

    文章目录 背景 实现方式 实现关键代码 结果验证图示 背景 在个人 App:Hi朋友中完善天气查询功能时,需要定位用户当前所在的城市,需要用到手机的定位功能.让用户打开天气查询页时,能够自动定位当前所 ...

  5. Android定位功能开发(1)——获取位置

    基于位置的服务包括三个方面:获取位置.地图服务.地理编码服务. 获取位置有两种方式,一种是通过GPS获得位置,精度高,耗电高,另一种是通过WLAN或通讯基站获得位置,精度低,耗电低.得到的位置信息是三 ...

  6. Android定位功能开发(3)——地图服务(地图点与经纬度)

    基本的地图服务包括三项功能: 让地图显示某个经纬度位置: 获取地图上某个点的经纬度: 在地图上标注出某个位置. 要让地图显示某个经纬度位置,步骤是:获取BaiduMap对象.设置位置.动画显示. 代码 ...

  7. android定位:获取当前位置的经纬度

    Android定位主要使用的是基于位置服务(Location Based Service)技术,有了 Android 系统作为载体,我们可以利用定位出的位置进行许多丰富多彩的操作,比如定位城市,根据我 ...

  8. Android 百度地图开发(二)--- 定位功能之MyLocationOverlay,PopupOverlay的使用

    转载请注明出处http://blog.csdn.net/xiaanming/article/details/11380619 这一篇文章主要讲解的是百度地图的定位功能,然后还有MyLocationOv ...

  9. Android利用百度地图API实现定位功能(记录)

    本篇主要介绍一下如何使用百度地图API来实现定位以及地图的基本使用. 效果图如下: 步骤如下: 一.申请APIKey. (1)注册百度账号并申请开发者资质:http://developer.baidu ...

最新文章

  1. python基础代码事例-学习笔记:python3,代码。小例子习作(2017)
  2. Anaconda3自带jupyter
  3. S3c2440A平台HIVE注册表+binfs的实现
  4. 敏捷图书排行 (2011年修订)【转】
  5. Casbin荣获2021年度“科创中国”开源创新榜优秀开源产品
  6. 重装系统后出现服务器正在运行中,win7系统重装完后怎么一直显示正在启动 - 卡饭网...
  7. php 个人摄影,展示个人摄影作品的12种方式(ZT)
  8. 手机如何借用笔记本网络上网
  9. 解析低压差线性稳压器(LDO)在摄像头应用中的创新设计
  10. iOS compare用法
  11. Python 构成三角形
  12. 字符串分段组合python123_boost python分段fau
  13. 【信息量判别块:语义监督:GAN:IVIF】
  14. 度过有意义的生命(上)
  15. HTML5 Canvas可拖动的弹性大树摇摆动画
  16. 吃货 JYY / Foodie
  17. Ros 与 STM32 之Ros串口同设备USB固定
  18. 144基于springboot的易卖网商城源码下载
  19. react 引入轮播插件_简单实现 babelpluginimport 插件
  20. EasyRecovery for Mac(数据恢复软件)中文免费版

热门文章

  1. 人生有四苦:我选择了承受痛苦
  2. 快递单号查询、倒计时和发送短信效果
  3. CATIA软件使用技巧之层叠成形的闭合点
  4. Minitool安装出现的问题
  5. Tomcat官方文档中文版
  6. HPL HPCG benchmark test
  7. 蓝奏云批量下载 with urllib3 — Python39
  8. 取水口取水监测计量、取水口取水量在线监测、取水在线监控
  9. 超详细的(视频)人脸情感特征提取教程【Python】
  10. 基于STM32F407的俄罗斯方块游戏代码分析