Fused Location Provider意外行为

时间:2014-10-05 07:49:47

标签: android gps google-play-services android-location location-services

这是我注册我的应用以接收位置更新的方式:

mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(Consts.ONE_MINUTE * 10);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setFastestInterval(Consts.ONE_MINUTE);

Builder builder = new GoogleApiClient.Builder(context);
builder.addApi(ActivityRecognition.API);

mGoogleApiClient = builder.addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

mGoogleApiClient.connect();

....
....

@Override
public void onConnected(Bundle connectionHint) {
   LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, locationUpdatespendingInent);
}

我的待处理意图几乎按照确切的请求间隔在后台调用...

到目前为止一切顺利。

问题:当WIFI被禁用/未连接到任何网络,或者没有启用3G / 4G网络数据时 - 融合位置提供商不提供新的位置更新!!

我的位置访问设置已打开,GPS卫星和WI-FI&检查移动网络位置。

更大的问题:有时在这种情况下,我会通过待处理的意图接收位置更新回调,但是它知道的最后一个位置(即使是一小时前,我也是很长很远离那个地方很远的地方)

根据PRIORITY_BALANCED_POWER_ACCURACY的文档:

  

与setPriority(int)一起使用以请求“块”级别的准确性。   块级精度被认为是大约100米的精度。使用这种粗略的精度通常会消耗更少的功率。

我期待融合位置提供商在没有其他选择时打开GPS,或者如果他没有其他选择,至少不会提供新的位置更新。

另一个不可预测和令人不安的问题:

我将PRIORITY_BALANCED_POWER_ACCURACY更改为PRIORITY_HIGH_ACCURACY以查看其行为(24小时)。所有间隔保持不变(更新之间间隔10分钟)。即使在没有网络/ SIM卡的手机中也确实收到了准确的位置,但是 - 电池耗尽快!当我查看电池历史时,我惊讶地看到 GPS无线电一直处于完全传输模式!!!! 我在日志中也看到每分钟收到一个位置,甚至我每十分钟请求一次位置(我没有任何其他安装的应用程序打开GPS接收位置..)

我注意到在多个设备(例如Moto X 2013,HTC One X,Nexus 5)上的这种行为,所有设备都带有最新的Google Play服务(版本6.1.11)和Android KITKAT 4.4.4

我的应用程序在很大程度上取决于用户当前位置,并且只要用户登录,就会定期在指定的时间间隔内接收位置更新,因此我不想使用PRIORITY_HIGH_ACCURACY模式,以防止电池漏..

我的问题:

  • 是融合位置提供商,如果设置为使用PRIORITY_BALANCED_POWER_ACCURACY接收更新并且没有任何WI-FI或手机信息塔信息,则假设完全使用GPS?

  • 如果确实如此,那么我做错了什么?

  • 为什么我得到这种误导性的位置更新不正确? (正如我在“更大问题”一节中所解释的那样......

  • 为什么GPS广播一直打开,而不是在我使用PRIORITY_HIGH_ACCURACY参数时间隔10分钟打开? (我没有其他安装的应用程序更快地触发位置更新..)

4 个答案:

答案 0 :(得分:19)

对于指定的问题,

1。 是融合位置提供商,如果设置为使用PRIORITY_BALANCED_POWER_ACCURACY接收更新并且没有任何WI-,则假设完全使用GPS FI或手机信息塔信息?的&安培;
2。 如果有,那么我做错了什么?

显然,在文档中的任何位置都没有指定明确的唯一源。使用PRIORITY选项,即使通过代码,获得的location的“来源”也是“融合”。
[location.getProvider()返回:“融合”] 我已经看到只有当LocationRequest具有PRIORITY_HIGH_ACCURACY时才使用GPS。所以它在其他条件下不使用GPS。

4。 为什么GPS广播一直打开,而不是在我使用PRIORITY_HIGH_ACCURACY参数时间隔10分钟打开? (我没有其他安装的应用程序更快地触发位置更新..)

最快间隔设定为1分钟。根据我的理解,当最快间隔的值的持续时间短于setInterval的值时,setFastestInterval优先于setInterval
在你的情况下,1分钟对10 关于没有其他已安装的应用程序触发位置更新,它仅作为示例给出,并没有明确指定只有那种情况。

  

这可以控制应用程序收到的最快速率   位置更新,在某些情况下可能比setInterval(long)更快   情况(例如,如果其他应用程序正在触发位置   更新)。

所以,PRIORITY_HIGH_ACCURACY会发生什么,它在最快的间隔设置上请求location - 1分钟,使用GPS(专门的类型)。

3。 为什么我收到这些误导性的位置更新不正确? (正如我在“更大问题”一节中所解释的那样......

还需要检查pendingIntent机制的代码。虽然可能有一些事情要注意:
您可以添加location.getTime()以确保并验证获取位置的时间。如果范围内没有wifi-cell塔并且使用PRIORITY_BALANCED_POWER_ACCURACY,则很可能没有更新 第一个位置的块级准确度,在调用“lastKnown”时使用将无济于事。

电池消耗量是因为GPS和1分钟更新的结合。尝试将最快间隔设置为5或10分钟(如果适合您的实施),但如果您需要绝对准确的位置,则PRIORITY_BALANCED_POWER可能无效。我通常会添加对onLocationChanged中获取的位置的检查,并根据该位置,在LocationRequest中切换优先级。它肯定有助于获得一个位置,除非我在一个没有GPS视线和Wifi网络的建筑物内。

答案 1 :(得分:4)

我建议您一起使用AlarmManagerFusedLocationProvider,以便每隔10分钟发出AlarmManager个火警,以便开始更新位置。

获得更新位置后,断开位置客户端。您不需要通过在LocationRequest中设置间隔时间来保持其一直运行,而是可以使用AlarmManager在每个时间间隔调用该过程。

在这种机制中,您将获得以下好处,以解决您的问题:

  • GPS收音机将在检索位置时保持打开状态几秒钟,因为您将在获得第一次位置更新后断开连接。因此GPS收音机不会一直保持打开状态,因此电池将被保存。
  • 您可以在每10分钟获得新位置,而不会弄乱旧位置或其他东西。

我希望它会有所帮助。

答案 2 :(得分:3)

Cell tower覆盖了几英里的区域,因此它们不是最适合获取位置的区域。使用位置时,请查看位置准确性。

@Override
public void onLocationChanged(Location location) {
    //it happens
    if (location == null) {
        return;
    }
    // all locations should have an accuracy
    if (!location.hasAccuracy()) {
        return;
    }
    // if its not accurate enough don't use it
    // this value is in meters
    if (location.getAccuracy() > 200) {
        return;
    }
}

您可以将广播接收器置于网络状态,当没有连接时,您可以使用priority_high_accuracy重新启动您的位置提供商,仅当用户启用GPS时才会使用GPS,否则它会回到wifi和手机信号塔上。

<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>

/** Checks whether the device currently has a network connection */

private boolean isDeviceOnline() {
    ConnectivityManager connMgr = (ConnectivityManager) activity
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    if (networkInfo != null && networkInfo.isConnected()) {
        return true;
    }
    return false;
}

答案 3 :(得分:0)

要更新GPS坐标,您还可以使用GPS和WI-FI提供商。用于更新位置使用以及最小距离参数。我将为您提供小型GPS服务示例。

答案:

1)PRIORITY_BALANCED_POWER_ACCURACY not使用GPS。

2)使用GPS和WI-FI检测位置。

3)PRIORITY_BALANCED_POWER_ACCURACY可能是因为区域内没有WI-FI。

代码示例:

public class GPSservice extends Service implements LocationListener {


    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 2;

    private static final long MIN_TIME_BW_UPDATES = 1000 * 1;

    double latitude, longitude;

    boolean isGPSEnabled = false;

    boolean isNetworkEnabled = false;

    boolean canGetLocation = false;

    Location location;

    protected LocationManager locationManager;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        getLocation();

        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onLocationChanged(Location location) {
        new LocationReceiver(location, getApplicationContext());
    }


    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    public Location getLocation() {
        try {
            locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

            // getting GPS status
            isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled) {
                Log.d("Network", "NO network");
            } else {
                this.canGetLocation = true;
                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    Log.d("Network", "Network");
                    if (locationManager != null) {
                        location = locationManager
                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
                        }
                    }
                }
                if (isGPSEnabled) {
                    if (location == null) {
                        locationManager.requestLocationUpdates(
                                LocationManager.GPS_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        Log.d("GPS Enabled", "GPS Enabled");
                        if (locationManager != null) {
                            location = locationManager
                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return location;
    }
}