Android申请地理位置时的流程及源代码分析
来源:互联网 发布:苹果mac怎么压缩文件 编辑:程序博客网 时间:2024/05/18 19:19
1.首先看一下在android应用中是如何获取Location的
LocationManager locationManager; String serviceName = Context.LOCATION_SERVICE; locationManager = (LocationManager) this.getSystemService(serviceName); // 查找到服务信息 Criteria criteria = new Criteria(); //定义标准 criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度 criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(true); criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗 String provider = locationManager.getBestProvider(criteria, true); // 获取最好的provider,就是在此时检测权限的 Location location = locationManager.getLastKnownLocation(provider); // 通过GPS获取位置 updateToNewLocation(location); // 设置监听器,自动更新的最小时间为间隔N秒(1秒为1*1000,这样写主要为了方便)或最小位移变化超过N米 locationManager.requestLocationUpdates(provider, 100 * 1000, 500, locationListener);
首先通过getSystemService找到LocationManager服务,然后设定需要的地理位置的一些标准。然后通过LocationManager中的getBestProvider函数调用LocationManagerService.java中的getBestProvider函数来找到最好的Provider,其中Provider有四种:
1)NETWORK_PROVIDER:通过信号塔和wifi接入点来定位
2)GPS_PROVIDER:需要ACCESS_FINE_LOCATION权限,是通过卫星定位
3)PASSIVE_PROVIDER:需要ACCESS_FINE_LOCATION权限
4)FUSED_PROVIDER:融合所有的位置信息提供最佳的地理位置
2.下面来看一下getBestProvider函数
public String getBestProvider(Criteria criteria, boolean enabledOnly) { String result = null; List<String> providers = getProviders(criteria, enabledOnly); if (!providers.isEmpty()) { result = pickBest(providers); if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); return result; } providers = getProviders(null, enabledOnly); if (!providers.isEmpty()) { result = pickBest(providers); if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); return result; } if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); return null; }
首先通过根据标准Criteria通过getProviders()方法查找所有的符合的providers,如果providers不为空,那么通过pickBest函数,在providers列表中选择一个最好的provider,pickBest函数如下:
private String pickBest(List<String> providers) { if (providers.contains(LocationManager.GPS_PROVIDER)) { return LocationManager.GPS_PROVIDER; } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) { return LocationManager.NETWORK_PROVIDER; } else { return providers.get(0); } }
意思就是如果providers列表中存在GPS则首先选择GPS,如果没有GPS,则首先选择NET_PROVIDER,如果两个都么有,那么就选择providers中的第一个。(接上一段)如果providers列表为空,那么则通过getProviders(null, enabledOnly)来获取无标准的providers,接着做上面同样的事情。如果此时providers列表还是为空,那么返回null。
3.getProviders函数
public List<String> getProviders(Criteria criteria, boolean enabledOnly) { int allowedResolutionLevel = getCallerAllowedResolutionLevel(); ArrayList<String> out; int uid = Binder.getCallingUid();; long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { out = new ArrayList<String>(mProviders.size()); for (LocationProviderInterface provider : mProviders) { String name = provider.getName(); if (LocationManager.FUSED_PROVIDER.equals(name)) { continue; } if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) { if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) { continue; } if (criteria != null && !LocationProvider.propertiesMeetCriteria( name, provider.getProperties(), criteria)) { continue; } out.add(name); } } } } finally { Binder.restoreCallingIdentity(identity); } if (D) Log.d(TAG, "getProviders()=" + out); return out; }
该函数首先通过getCallerAllowedResolutionLevel()函数来获取应用允许的位置信息分辨率(即权限审查)。getCallerAllowedResolutionLevel()函数如下:
private int getCallerAllowedResolutionLevel() { return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid()); }
该函数简单的调用了getAllowedResolutionLevel(),函数如下:
private int getAllowedResolutionLevel(int pid, int uid) { if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, pid, uid) == PackageManager.PERMISSION_GRANTED) { return RESOLUTION_LEVEL_FINE; } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) == PackageManager.PERMISSION_GRANTED) { return RESOLUTION_LEVEL_COARSE; } else { return RESOLUTION_LEVEL_NONE; } }
分析以下这张图:
图中ContextImpl类和ContextWrapper类中checkPermission函数如下:
ContextImpl类中的checkPermission函数如下:经分析可知最终调用的还是ActivityManagerService类中的checkPermission()。
public int checkPermission(String permission, int pid, int uid) { if (permission == null) { throw new IllegalArgumentException("permission is null"); } try { return ActivityManagerNative.getDefault().checkPermission( permission, pid, uid); } catch (RemoteException e) { return PackageManager.PERMISSION_DENIED; } }
ContextWrapper类中checkPermission函数如下:其中mBase是Context的实例,其实调用的是ContextImpl类中的checkPermission函数。
public int checkPermission(String permission, int pid, int uid) { return mBase.checkPermission(permission, pid, uid); }
所以,最终调用checkPermission函数为PackageManagerService.java中的checkPermission函数。getAllowedResolutionLevel()进行权限检查后回去应用申请的权限,如果应用细粒度和粗粒度的权限都申请了,那么返回细粒度的分辨率即可。
对权限就分析到这吧
- Android申请地理位置时的流程及源代码分析
- BasicManageProfile申请设备管理user的流程分析
- Android 6.0 Reboot 流程源代码分析
- Android 6.0 Reboot 流程源代码分析
- Android 6.0 Reboot 流程源代码分析
- Android 6.0 Reboot 流程源代码分析
- 申请 Android MapView 的apiKey流程
- 申请 Android MapView 的apiKey流程
- android M 运行时权限申请流程
- android 6.0 运行时权限申请流程
- android微信支付申请流程及开发过程
- Peercast收听电台的源代码流程分析
- ModelAttribute注解的源代码分析流程
- Android Wifi的工作流程 及常见问题分析
- Android系统的启动流程分析及如何看源码
- Android的开机流程及对应源码位置分析
- Android的开机流程及对应源码位置分析
- Android注解AndroidAnnotation的使用及实现流程分析
- mysql导出excel文件的方法
- VS2010创建基于对话框的项目后,打开此项目文件,内部各个文件所代表的含义
- JDK的安装和配置
- 022:函数:递归是神马
- The PING of Death and Other DoS Network Attacks
- Android申请地理位置时的流程及源代码分析
- 手机卫士-11
- 后考研时代的前端学习
- 导弹拦截(最长下降子序列)变形
- 牛二
- 71. PHP 抽象类
- java程序发送邮件以及可能出现的问题
- HDU 3714 Error Curves(3分)
- JAVA:运算符与表达式