最近接触了一些GPS定位的功能,有些东西还是可以分享一下的,都是我在开发过程中遇到的问题。
权限
GPS精确定位权限:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
WIFI粗略定位权限:<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
定位服务
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
openGPS(this);
return;
}
public void openGPS(Context context)
{
new AlertDialog.Builder(this).setTitle("温馨提示")
.setMessage("请点击“确定”按钮,勾选“卫星位置服务”项,再重新打开程序")
.setCancelable(false)
.setPositiveButton("确定", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
Intent toit = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(toit);
finish();
System.exit(0);
}
}).show();
}
这里是为了防止用户没有打开手机的定位服务,引导用户打开手机的定位服务。
我做的这个项目对定位要求非常高,所以我把定位放在服务里边,一直定位,而且是GPS定位。
Criteria
Criteria 类可以帮助开发者选择Provider,当然我觉的有点鸡肋,因为最常用的就是网络定位和GPS定位,优缺点很明显,开发者可以自己选择。
// 构建位置查询条件
Criteria criteria = new Criteria();
// 查询精度:高
criteria.setAccuracy(Criteria.ACCURACY_FINE);
// 是否查询海拨:否
criteria.setAltitudeRequired(false);
// 是否查询方位角:否
criteria.setBearingRequired(false);
// 是否允许付费:是
criteria.setCostAllowed(true);
// 电量要求:低
criteria.setPowerRequirement(Criteria.POWER_LOW);
// 返回最合适的符合条件的provider,第2个参数为true说明,如果只有一个provider是有效的,则返回当前provider
provider = locationManager.getBestProvider(criteria,true);
添加监听
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 0, netWorkListener);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
1000, 0, gpsListener);
mLocationManager.addGpsStatusListener(statusListener);
provider:定位方式
minTime:更新需要的时间
minDistance:更新需要的距离
listener:监听器
addGpsStatusListener:添加状态监听器(主要可以看连接卫星数)
private final GpsStatus.Listener statusListener = new GpsStatus.Listener()
{
public void onGpsStatusChanged(int event)
{
// GPS状态变化时的回调,如卫星数
GpsStatus status = mLocationManager.getGpsStatus(null); // 取当前状态
count = 0;
if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS)
{
int maxSatellites = status.getMaxSatellites();
Iterator<GpsSatellite> it = status.getSatellites().iterator();
while (it.hasNext() && count <= maxSatellites)
{
// 计算卫星数量
it.next();
count++;
}
}
}
};
private class MyLocationListener implements LocationListener
{
@Override
public void onLocationChanged(Location location)
{
LocationService.location = location;
String provider = location.getProvider();
if (provider.equals(LocationManager.GPS_PROVIDER)
&& !isNetWorkRemove && location != null)
{
mLocationManager.removeUpdates(netWorkListener);
isNetWorkRemove = true;
}
// Service与Activity通过广播通信
Intent intent = new Intent();
intent.putExtra("lat", location.getLatitude());
intent.putExtra("lng", location.getLongitude());
intent.putExtra("count", count);
intent.setAction(Constant.RECEIVER_ACTION_LOCATION);
sendBroadcast(intent);
}
@Override
public void onProviderDisabled(String arg0)
{
System.out.println("GPS禁用时触发");
}
@Override
public void onProviderEnabled(String arg0)
{
System.out.println("GPS开启时触发");
}
@Override
public void onStatusChanged(String arg0, int status, Bundle arg2)
{
if (LocationProvider.OUT_OF_SERVICE == status)
{
Toast.makeText(getApplicationContext(), "GPS服务丢失,切换至网络定位",
Toast.LENGTH_SHORT).show();
mLocationManager
.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0,
netWorkListener);
isNetWorkRemove = false;
}
}
}
注意事项
1.使用GPS定位的时候,要在空旷的室外,室内很难定到,第一次时间大约1分钟多,这得看你的手机芯片了。
2.为了快速拿到位置信息,可以使用locationManager.getLastKnownLocation(provider)
这是使用了缓存中上一次的定位信息,注意,很有可能是null,所以在使用的时候,先判断一下。
3.即使位置未变,坐标也是在变化的,所以考虑下什么时候获取坐标。
4.坐标飘移现象,除了硬件问题和环境问题,我觉的无法避免飘移,只能通过添加地图,或者一些算法来减小损失。
5.如果你的速度经常变化,或者从室内来到室外,第一次location的变化通常是不准确的,理论上停止一段时间坐标离散会趋近与正确的点。