前言
Android 系统提供了地理位置服务相关的API方便开发者去获得当前地理位置。在android framework层的android.loaction包下面主要提供了如下两个类来帮助开发者来获取地理位置信息。
LocationManager:用于获取地理位置的经纬度信息
Geocoder:根据经纬度获取详细地址信息 / 根据详细地址获取经纬度信息
今天我们通过简单例子来详细说明使用以上两个类来帮助开发者获取地理位置信息
注意:在使用地理位置时请添加上以下几个权限:
LocationManager
该类提供了访问地理位置的服务,可以获取上一次最新的地理位置信息,也可以注册监听事件来周期性的获得设备更新的地理位置信息。在获取地理位置信息时我们必须了解一下两个知识点:
1 provider
2 LocationListener
provider
位置信息的提供者,android系统一般提供三种方式来获取地理位置信息。分别如下:
GPS_PROVIDER:通过gps来获取地理位置的经纬度信息,优点:获取地理位置信息精确度高,缺点:只能在户外使用,获取经纬度信息耗时,耗电。
NETWORK_PROVIDER:通过移动网络的基站或者WiFi来获得地理位置,优点:只要有网络,获取速度快,在室内室外都可以使用。缺点:精确度不高。
PASSIVE_PROVIDER:被动的接收更新的地理位置信息,而不用自己主动请求地理位置。
LocationManager类中提供了以下几种方法来获得地理位置提供者。
public List
以上方法返回当前设备所有地理位置提供者。
public List
以上方法当参数为true时,返回的时当前设备可使用的位置提供者;当参数为false时和上面那个方法一样,返回所有的位置提供者。
public String getBestProvider(Criteria criteria, boolean enabledOnly);
以上方法返回当前设备最符合指定条件的位置提供者,第一个参数criteria用于指定条件,第二个参数表示是否返回当前设备可用的位置提供者。现在来分析这两个参数。
public List
以上方法也是返回当前符合条件的所有可用的provider。
Criteria
该类用于指定帅选最符合条件的地理位置提供者,根据Cirteria指定的条件,设备会自动选择哪种location provider。Criteria类中提供如下方法来指定条件。
public void setAccuracy(int accuracy):位置解析精确度,参数Criteria.ACCURACY_FINE:表示高精确度。Criteria.ACCURACY_COARSE:表示模糊精确度。
public void setAltitudeRequired(boolean altitudeRequired ):是否要求海拔信息。
public void setBearingRequired(boolean bearingRequired):是否要求方向信息。
public void setCostAllowed(boolean costAllowed):是否允许收费。
public void setSpeedRequired(boolean speedRequired):是否要求速度信息。
public void setBearingRequired(boolean bearingRequired):是否要求方向信息。
public void setPowerRequirement(int level):设置电池消耗要求,参数 Criteria. NO_REQUIREMENT, Criteria. POWER_LOW, Criteria. POWER_MEDIUM, Criteria. POWER_HIGH。分别表示 :无、低、中、高,。
public void setBearingAccuracy(int accuracy):设置方向的精准度。参数 Criteria.NO_REQUIREMENT, Criteria.ACCURACY_LOW, Criteria.ACCURACY_HIGH。分别表示:无,低,高。
public void setSpeedAccuracy(int accuracy):设置速度的精准度。参数同上。
public void setHorizontalAccuracy(int accuracy):设置水平方向的精准度。参数同上。
public void setVerticalAccuracy(int accuracy):设置垂直方向的精准度。参数同上。
Criteria类该怎么使用?代码示例如下:
criteria.setAccuracy(Criteria.ACCURACY_FINE);//设置定位精准度
criteria.setAltitudeRequired(false);//是否要求海拔
criteria.setBearingRequired(true);//是否要求方向
criteria.setCostAllowed(true);//是否要求收费
criteria.setSpeedRequired(true);//是否要求速度
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);//设置电池耗电要求
criteria.setBearingAccuracy(Criteria.ACCURACY_HIGH);//设置方向精确度
criteria.setSpeedAccuracy(Criteria.ACCURACY_HIGH);//设置速度精确度
criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);//设置水平方向精确度
criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH);//设置垂直方向精确度
//返回满足条件的,当前设备可用的location provider,当第二个参数为false时,返回当前设备所有provider中最符合条件的那个provider(但是不一定可用)。
String mProvider = mLocationManager.getBestProvider(criteria,true);
LocationListener
LocationManager类中提供了如下方法来获得最新一次更新的地理位置信息。
public Location getLastKnownLocation(String provider);
以上方法可以传入相应的 location provider来获得当前地理位置信息。代码示例如下:
LocationManager mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
mLocationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
getLastKnownLocation()方法只能一次性的获得当前最新的地理位置,但是它不能实时的监听地理位置的变化情况。Android给开发者提供了一个接口监听类LocationListener来实时监听当前设备的地理位置变化情况。
LocationListener用于监听当地理位置有改变时来接收通知的接口类。在使用该监听之前您必须要用LocationManager类中的如下方法来注册该监听事件。
public void requestLocationUpdates(String provider, long minTime, float minDistance,
LocationListener listener)
以上注册监听方法,参数一:位置提供者;参数二:位置更新最短时间(单位ms);参数三:位置更新最短距离(单位m);参数四:LocationListener监听器对象。
LocationListener接口类中有如下方法:
public interface LocationListener {
//当位置改变时调用.
void onLocationChanged(Location location);
//当location provider的状态改变时,该方法被调用。状态有三种:
//LocationProvider#OUT_OF_SERVICE:无服务
//LocationProvider#TEMPORARILY_UNAVAILABLE:provider不可用
//LocationProvider#AVAILABLE:provider可用
void onStatusChanged(String provider, int status, Bundle extras);
//当provider可用时调用,比如gps可用时就会调用该方法。
void onProviderEnabled(String provider);
//当provider不可用时调用该方法。比如gps未打开,gps不可用就会调用该方法。
void onProviderDisabled(String provider);
}
Geocoder
该类用于获取地理位置的前向编码和反向编码,前向编码是根据地址获取经纬度;反向编码是根据经纬度获取对应的详细地址。Geocoder 请求的是一个后台服务,但是该服务不包括在标准android framework中。因此如果当前设备不包含location services,则Geocoder返回的地址或者经纬度为空。当然你可以使用 Geocoder#isPresent()方法来判断当前设备是否包含地理位置服务。由于国内使用不了Google Services服务,因此一般的手机厂商都会在自己的手机内内置百度地图服务,或者高德地图服务来替代Google Services服务。
Geocoder类提供一下几个方法:
public static boolean isPresent()
判断当前设备是否内置了地理位置服务。返回true表示Geocoder地理编码可以使用,否则不可使用。国内一般用不了Google services,所以一般使用百度地图或者高德地图来代替。
public List
getFromLocation(double latitude, double longitude, int maxResults)以上方法根据经纬度返回对应的地理位置信息。参数一:经度;参数二:维度;参数三:返回地址的数目(由于同一经纬度可能对于多个地址,该参数取1~5之间)。
public List
getFromLocationName(String locationName, int maxResults)以上方法根据具体地址来获取相应的地理位置信息。参数一:地址;参数二:返回地址的数目(取1~5之间)。
好了知识大略的补充一下后请看一个小Demo:
package com.example.administrator.getlocation;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TextView tvLocation;
private TextView tvAddress;
private Geocoder geocoder;
private List addressList;
private StringBuilder sb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUi();
initData();
}
private void initData() {
// 获取经纬度坐标
// 1 获取位置管理者对象
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 2 通过lm获得经纬调度坐标
// (参数: provider(定位方式 提供者 通过 LocationManager静态调用),
// minTime(获取经纬度间隔的最小时间 时时刻刻获得传参数0),
// minDistance(移动的最小间距 时时刻刻传0),LocationListener(监听))
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
// 获取经纬度主要方法
double latitude = location.getLatitude();
double longitude = location.getLongitude();
tvLocation.setText("latitude"+latitude+" "+"longitude"+longitude);
sb = new StringBuilder();
geocoder = new Geocoder(MainActivity.this);
addressList = new ArrayList();
try {
// 返回集合对象泛型address
addressList= geocoder.getFromLocation(latitude,longitude,1);
if (addressList.size() > 0) {
Address address = addressList.get(0);
for (int i = 0; i < address.getMaxAddressLineIndex(); i++) {
sb.append(address.getAddressLine(i)).append("\n");
}
sb.append(address.getFeatureName());//周边地址
}
tvAddress.setText("当前位置"+sb.toString());
;
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
//状态发生改变监听
}
@Override
public void onProviderEnabled(String s) {
// GPS 开启的事件监听
}
@Override
public void onProviderDisabled(String s) {
// GPS 关闭的事件监听
}
});
}
private void initUi() {
tvLocation = (TextView) findViewById(R.id.tv_location);
tvAddress = (TextView) findViewById(R.id.tv_address);
}
}
贴图如下
注:
此处网络定位可能不精确如果想获得精确位置可把提供者改为Gps定位即可