最近接触了一些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的变化通常是不准确的,理论上停止一段时间坐标离散会趋近与正确的点。