说到做手机定位,大家想到的肯定是高德地图或者是百度地图,因为这些位置服务商可以根据我们返回的基站数据,WIFI数据,以及我们GPS的定位,来确定我们更加精确的位置信息。不过其中的GPS定位,其实Android原生系统中就带着一套。虽然我们多数时候都不会直接用它,但作为一个严谨的开发者,我们有必要进行相应的了解。另外,在一些特殊环境下,比如专属设备中,专属网络中,可能我们并不能访问到三方网站或者接入三方SDK,这时候就需要原生GPS来进行定位操作了。
下面我从相关定位工具和示例代码两块对GPS定位进行介绍。
1.相关工具介绍
<1>定位条件器Criteria
定位条件器用于设置定位的前提条件,比如精度、速度、海拔、方位等信息,有以下5个常用参数。
- setAccuracy:设置定位精度。有两个取值,Criteria.ACCURACY_FINE表示精度高,Criteria.ACCURACY_COARSE表示精度低。
- setSpeedAccuracy:设置速度精确度。速度精确度的取值见表1。
表1 | |
Criteria类的速度精确度 | 说明 |
ACCURACY_HIGH | 精度高,误差小于100米 |
ACCURACY_MEDIUM | 精度中等,误差在100米到500米之间 |
ACCURACY_LOW | 精度低,误差大于500米 |
- setAltitudeRequired:设置是否需要海拔信息。取值true表示需要,false表示不需要。
- setBearingRequired:设置是否需要方位信息。取值true表示需要,false表示不需要。
- setCostAllowed:设置是否允许运营商收费。取值true表示允许,false表示不允许。
- setPowerRequirement:这是对电源的需求。有3个取值,Criteria.POWER_LOW表示耗电低,Criteria.POWER_MEDIUM表示耗电中等,Criteria.POWER_HIGH表示好点高。
<2>定位管理器LocationManager
定位管理器用于获取定位信息的提供者、设置监听器,并获取最近一次的位置信息。定位管理器的对象从系统服务LOCATION_SERVICE获取。
- getBestProvider:获取最佳的定位提供者。第一个参数为定位条件器Criteria的实例,第二个参数取值true表示只要可用的。定位提供者的取值见表2。
表2 | ||
定位提供者的名称 | 说明 | 定位功能的开启状态 |
gps | 卫星定位 | 开启GPS功能 |
network | 网络定位 | 开启数据连接或WLAN功能 |
passive | 无法定位 | 为开启定位相关功能 |
- isProviderEnabled:判断指定的定位提供者是否可用。
- getLastKnownLocation:获取最近一次的定位地点。
- requestLocationUpdates:设置定位监听器。其中,第一个参数为定位提供者,第二个参数为位置更新的最小间隔时间,第三个参数为位置更新的最小距离,第四个参数为定位监听器示例。
- removeUpdates:移除定位监听器。
- addGpsStatusListener:添加定位状态的监听器。该监听器需实现GpsStatus.Listener接口的onGpsStatusChanged方法。
- removeGpsStatusListener:移除定位状态的监听器。
<3>定位监听器Locationistener
定位监听器用于监听定位信息的变化事件,如定位提供者的开关、位置信息发生变化等。
- onLocationChanged:在位置地点发生变化时调用。在此可获取最新的位置信息。
- onProviderDisabled:在定位提供者被用户关闭时调用。
- onProviderEnabled:在定位提供者被用户开启时调用。
- onStatusChanged:在定位提供者的状态变化时调用。定位提供者的状态取值见表3。
表3 | |
LocationProvider类的状态类型 | 说明 |
OUT_OF_SERVICE | 在服务范围外 |
TEMPORARILY_UNAVAILABLE | 暂时不可用 |
AVAILABLE | 可用状态 |
2.相关代码示例
添加权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
MainActivity.java
public class MainActivity extends WaterPermissionActivity {
private final static String TAG = "LocationActivity";
private TextView tv_location;
private String mLocation = "";
private LocationManager mLocationMgr; // 声明一个定位管理器对象
private Criteria mCriteria = new Criteria(); // 声明一个定位准则对象
private Handler mHandler = new Handler(); // 声明一个处理器
private boolean isLocationEnable = false; // 定位服务是否可用
@Override
protected MvcBaseModel getModelImp() {
return null;
}
@Override
protected int getContentLayoutId() {
return R.layout.activity_main;
}
@Override
protected void initWidget() {
tv_location = findViewById(R.id.tv_location);
checkGpsIsOpen(this, "需要打开定位功能才能查看定位结果信息");
}
@Override
protected void onResume() {
super.onResume();
requestPermission(ACCESS_COARSE_LOCATION);
}
@Override
protected void doAccessCoarseLocation() {
requestPermission(ACCESS_FINE_LOCATION);
}
@Override
protected void doAccessFineLocation() {
mHandler.removeCallbacks(mRefresh); // 移除定位刷新任务
initLocation();
mHandler.postDelayed(mRefresh, 100); // 延迟100毫秒启动定位刷新任务
}
// 初始化定位服务
private void initLocation() {
// 从系统服务中获取定位管理器
mLocationMgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 设置定位精确度。Criteria.ACCURACY_COARSE表示粗略,Criteria.ACCURACY_FIN表示精细
mCriteria.setAccuracy(Criteria.ACCURACY_FINE);
// 设置是否需要海拔信息
mCriteria.setAltitudeRequired(true);
// 设置是否需要方位信息
mCriteria.setBearingRequired(true);
// 设置是否允许运营商收费
mCriteria.setCostAllowed(true);
// 设置对电源的需求
mCriteria.setPowerRequirement(Criteria.POWER_LOW);
// 获取定位管理器的最佳定位提供者
String bestProvider = mLocationMgr.getBestProvider(mCriteria, true);
if (mLocationMgr.isProviderEnabled(bestProvider)) { // 定位提供者当前可用
tv_location.setText("正在获取" + bestProvider + "定位对象");
mLocation = String.format("定位类型=%s", bestProvider);
beginLocation(bestProvider);
isLocationEnable = true;
} else { // 定位提供者暂不可用
tv_location.setText("\n" + bestProvider + "定位不可用");
isLocationEnable = false;
}
}
// 设置定位结果文本
private void setLocationText(Location location) {
if (location != null) {
String desc = String.format("%s\n定位对象信息如下: " +
"\n\t其中时间:%s" + "\n\t其中经度:%f,纬度:%f" +
"\n\t其中高度:%d米,精度:%d米",
mLocation, getNowDateTimeFormat(),
location.getLongitude(), location.getLatitude(),
Math.round(location.getAltitude()), Math.round(location.getAccuracy()));
Log.d(TAG, desc);
tv_location.setText(desc);
} else {
tv_location.setText(mLocation + "\n暂未获取到定位对象");
}
}
// 开始定位
@SuppressLint("MissingPermission")
private void beginLocation(String method) {
// 检查当前设备是否已经开启了定位功能
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "请授予定位权限并开启定位功能", Toast.LENGTH_SHORT).show();
return;
}
// 设置定位管理器的位置变更监听器
mLocationMgr.requestLocationUpdates(method, 300, 0, mLocationListener);
// 获取最后一次成功定位的位置信息
Location location = mLocationMgr.getLastKnownLocation(method);
setLocationText(location);
}
// 定义一个位置变更监听器
private LocationListener mLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
setLocationText(location);
}
@Override
public void onProviderDisabled(String arg0) {}
@Override
public void onProviderEnabled(String arg0) {}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
};
// 定义一个刷新任务,若无法定位则每隔一秒就尝试定位
private Runnable mRefresh = new Runnable() {
@Override
public void run() {
if (!isLocationEnable) {
initLocation();
mHandler.postDelayed(this, 1000);
}
}
};
@SuppressLint("MissingPermission")
@Override
protected void onDestroy() {
if (mLocationMgr != null) {
// 移除定位管理器的位置变更监听器
mLocationMgr.removeUpdates(mLocationListener);
}
super.onDestroy();
}
// 获取定位功能的开关状态
public static boolean getGpsStatus(Context ctx) {
// 从系统服务中获取定位管理器
LocationManager lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
// 检查定位功能是否打开,若未打开则跳到系统的定位功能设置页面
public static void checkGpsIsOpen(Context ctx, String hint) {
if (!getGpsStatus(ctx)) {
Toast.makeText(ctx, hint, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
ctx.startActivity(intent);
}
}
public static String getNowDateTimeFormat() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
}
同样的,有关动态权限的申请可以使用自己项目中的。