【android】Android定位功能开发(1)——获取位置
<p>基于位置的服务包括三个方面:获取位置、地图服务、地理编码服务。</p><p>获取位置有两种方式,一种是通过GPS获得位置,精度高,耗电高,另一种是通过WLAN或通讯基站获得位置,精度低,耗电低。得到的位置信息是三维的,包括经度、纬度、海拔。<br>地图服务实现的功能是将经纬度点显示在地图上,以及将地图上的点转化为经纬度。通过调用地图服务商(如谷歌、百度、高德等)的API接口,从其服务器上获取地图信息。<br>地理编码服务实现经纬度点转化为地址,以及地址转化为经纬度。实现方法是通过HTTP协议调用互联网上的地址服务。<br><img src="https://img2023.cnblogs.com/blog/662503/202303/662503-20230307095658900-1731292810.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p>获取位置是所有基于位置的服务的基础,Android获取位置使用LocationManager类。首先获取LocationManager的实例,然后一般要检查位置服务是否开启。如果未开启,就打开设置位置服务界面。如果已开启,再检查应用的定位权限是否允许。都通过了,就可以设置一个位置监听器,有了位置信息就会调用监听器的相应方法。设置监听器时可以设置位置监听的最小时间间隔和最小距离间隔,只有这两个条件都满足时才会有位置信息。流程和关键代码如下图:<br><img src="https://img2023.cnblogs.com/blog/662503/202303/662503-20230307095724915-552380156.png" alt="" loading="lazy"></p>
<p> </p>
<p>下面是一个获取位置的例子。例子的界面如下,最上面一行是两项设置,记录位置的最小时间间隔和最小距离,只有这两个条件同时满足,才会产生一个位置数据。第二行是两个按钮,分别启动和停止位置监听。再下面是一个文本,显示监听到的位置信息。</p>
<div> <img src="https://img2023.cnblogs.com/blog/662503/202303/662503-20230307095750377-1239665717.png" alt="" loading="lazy">
<p> </p>
<p> </p>
<p>例子中,首先要在onCreate中获取LocationManager实例,并检查设备是否开启了位置服务,代码如下:</p>
<div class="cnblogs_code">
<pre>manager =<span style="color: rgba(0, 0, 0, 1)"> (LocationManager)getSystemService(Context.LOCATION_SERVICE);
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
!<span style="color: rgba(0, 0, 0, 1)">manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
askLocationSettings();
}</span></pre>
</div>
<p>可以从手机最上面的功能栏中开启/关闭手机的位置服务,如下图:</p>
<div> <img src="https://img2023.cnblogs.com/blog/662503/202303/662503-20230307095841798-1162512391.png" alt="" loading="lazy">
<p> </p>
<p> 如果位置服务未开启,可以询问用户是否转到位置服务设置界面。位置服务设置界面通过Intent来启动,动作是android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS。代码如下:</p>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> askLocationSettings(){
AlertDialog.Builder builder </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> AlertDialog.Builder(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">);
builder.setTitle(</span>"开启位置服务"<span style="color: rgba(0, 0, 0, 1)">);
builder.setMessage(</span>"本应用需要开启位置服务,是否去设置界面开启位置服务?"<span style="color: rgba(0, 0, 0, 1)">);
builder.setPositiveButton(</span>"是", <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DialogInterface.OnClickListener() {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onClick(DialogInterface arg0, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> arg1) {
Intent intent </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainActivity.</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.startActivity(intent);
}
});
builder.setNegativeButton(</span>"否", <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DialogInterface.OnClickListener() {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onClick(DialogInterface arg0, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> arg1) {
Toast.makeText(MainActivity.</span><span style="color: rgba(0, 0, 255, 1)">this</span>, "No location provider to use"<span style="color: rgba(0, 0, 0, 1)">,
Toast.LENGTH_SHORT).show();
}
});
builder.show();
}</span></pre>
</div>
<p>位置服务设置界面如下:</p>
<div> <img src="https://img2023.cnblogs.com/blog/662503/202303/662503-20230307100022434-1153272970.png" alt="" loading="lazy">
<p>如果设备开启了位置服务,就可以创建一个位置信息监听器,在监听时需要传给LocationManager。在事件监听方法中将经度、纬度、高度、速度等位置信息输出。代码如下:</p>
<div class="cnblogs_code">
<pre>listener = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> LocationListener(){
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onLocationChanged(Location arg0) {
String txt </span>= "Longitude:" +<span style="color: rgba(0, 0, 0, 1)"> arg0.getLongitude()
</span>+ ", Latitude:" +<span style="color: rgba(0, 0, 0, 1)">arg0.getLatitude()
</span>+ ", Altitude" +<span style="color: rgba(0, 0, 0, 1)"> arg0.getAltitude()
</span>+ ", Speed:" +<span style="color: rgba(0, 0, 0, 1)"> arg0.getSpeed();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 经度,纬度,高度,速度</span>
tvResult.append(txt + "\n"<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onProviderDisabled(String arg0) {}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> onProviderEnabled(String arg0) {}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onStatusChanged(String arg0, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> arg1, Bundle arg2) {}
};</span></pre>
</div>
<p>启动位置监听需要调用LocationManager的requestLocationUpdates()方法,方法的第一个参数是位置服务提供者。一个设备上可能有多个位置服务提供者,比如gps,wifi,北斗等,所以要先根据定位需求寻找一个最匹配的提供者,使用的方法是LocationManager的getBestProvider()方法。另外,获取当前位置需要一定的时间,而有些应用又已启动就需要一个定位信息,此时可以使用上次使用时的最后已知位置。该位置保存在缓存中,可以通过LocationManager的getLastKnownLocation()方法获得。具体代码如下: </p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> startListening(){
Criteria crt </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Criteria(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 位置监听标准</span>
crt.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 水平精度高</span>
crt.setAltitudeRequired(<span style="color: rgba(0, 0, 255, 1)">true</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 需要高度</span>
String provider = manager.getBestProvider(crt, <span style="color: rgba(0, 0, 255, 1)">true</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 寻找最匹配的provider</span>
Location l = manager.getLastKnownLocation(provider); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 取最后已知位置,即缓存中的位置</span>
<span style="color: rgba(0, 0, 255, 1)">if</span>(l!=<span style="color: rgba(0, 0, 255, 1)">null</span>) tvResult.append(provider + "-LastKnown:" + l.toString() + "\n"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">long</span> period = Long.parseLong(etPeriod.getText().toString()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 最小时间间隔</span>
<span style="color: rgba(0, 0, 255, 1)">int</span> distance = Integer.parseInt(etDistance.getText().toString()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 最小距离</span>
manager.requestLocationUpdates(provider, period*1000, distance, listener); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开始监听</span>
tvResult.append(provider + "-Location listener started.\n"<span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p>Android6.0以上系统需要应用运行时进行动态权限申请,所以在开始监听位置前需要检查权限,如果没有许可就进行询问。主要代码是:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span> (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) !=<span style="color: rgba(0, 0, 0, 1)"> PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, </span><span style="color: rgba(0, 0, 255, 1)">new</span> String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 101<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<p>停止位置监听使用LocationManager的removeUpdates()方法,代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">manager.removeUpdates(listener);
tvResult.append(</span>"Location listener stoped.\n");</pre>
</div>
<p>监听位置需要在配置文件里声明权限:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">uses-permission </span><span style="color: rgba(255, 0, 0, 1)">android:name</span><span style="color: rgba(0, 0, 255, 1)">="android.permission.ACCESS_FINE_LOCATION"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">uses-permission </span><span style="color: rgba(255, 0, 0, 1)">android:name</span><span style="color: rgba(0, 0, 255, 1)">="android.permission.ACCESS_COARSE_LOCATION"</span> <span style="color: rgba(0, 0, 255, 1)">/></span></pre>
</div>
<p>例子中用到的相关类包括:</p>
<p>1)android.location.LocationManager类,方法有:</p>
<p>boolean isProviderEnabled(String provider):返回提供位置的provider是否开启,provider的取值一般为LocationManager.GPS_PROVIDER或LocationManager.NETWORK_PROVIDER<br>String getBestProvider(Criteria criteria, boolean enabledOnly):返回与要求最匹配的provider,criteria为精度等要求,enabledOnly为true时只匹配已开启的provider,返回值一般为LocationManager.GPS_PROVIDER、LocationManager.NETWORK_PROVIDER或LocationManager.PASSIVE_PROVIDER(从其他应用获得位置)<br>Location getLastKnownLocation(String provider):返回上次已知位置,是上次获取位置时存放在缓存中的,不一定准确反映现在位置。若provider未开启会返回null。<br>void requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener):注册当前Activity来接收provider提供的位置信息。位置信息周期性产生,最小时间间隔为minTime毫秒,最小距离间隔为minDistance米,产生后会调用listener的onLocationChanged方法。minTime越小,位置服务搜索越频繁,耗电越多,最好不要小于60000毫秒。此方法必须在主线程中调用。<br>void removeUpdates(LocationListener listener):移除位置监听器<br>void requestLocationUpdates(String provider, long minTime, float minDistance, PendingIntent intent):位置变化后以广播PendingIntent的形式通知,可以在子线程中调用。<br>void removeUpdates(PendingIntent intent):移除位置通知广播<br>2)android.location.Criteria类,方法有:</p>
<p>void setHorizontalAccuracy(int accuracy):设置水平精度要求,accuracy取值为Criteria.ACCURACY_HIGH,ACCURACY_MEDIUM,ACCURACY_LOW<br>void setAltitudeRequired(boolean altitudeRequired):设置是否需要高度数据<br>3)android.location.Location类,方法有:</p>
<p>double getLongitude():返回经度<br>double getLatitude():返回纬度<br>double getAltitude():返回高度<br>float getSpeed():返回速度,单位米/秒<br>4)android.location.LocationListener接口,方法有:</p>
<p>void onLocationChanged(Location location):位置变化时调用<br>void onProviderDisabled(String provider):用户关闭provider时调用<br>void onProviderEnabled(String provider):用户开启provider时调用<br>void onStatusChanged(String provider, int status, Bundle extras):provider状态变化时调用,如GPS信号无法获得等<br>【参考连接】</p>
<h1 id="articleContentId" class="title-article">Android定位功能开发(1)——获取位置</h1>
</div>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/opensmarty/p/17187076.html
頁:
[1]