web-dev-qa-db-ja.com

融合ロケーションプロバイダーの予期しない動作

これは、位置情報の更新を受信するためにアプリを登録する方法です:

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とモバイルネットワークの場所がチェックされます。

さらに大きな問題:その場合、時々、保留中のインテントを介してロケーション更新コールバックを受け取りますが、最後のロケーションを知っていました(1時間前であっても、私は長いですその場所から何マイルも離れた)

PRIORITY_BALANCED_POWER_ACCURACYのドキュメントによると:

「ブロック」レベルの精度を要求するためにsetPriority(int)と共に使用されます。ブロックレベルの精度は、約100メートルの精度と見なされます。このような粗い精度を使用すると、消費電力が少なくなることがよくあります。

フュージョンロケーションプロバイダーは、他に選択肢がない場合にGPSを開くか、少なくとも持っていない場合は少なくとも新しいロケーションの更新を提供しないことを期待しています。

別の予測不可能で邪魔な問題:

動作を確認するために、PRIORITY_BALANCED_POWER_ACCURACYPRIORITY_HIGH_ACCURACYに変更しました(24時間)。すべての間隔は同じままでした(更新間隔は10分)。ネットワーク/ SIMカードのない携帯電話でも正確な位置情報が得られますが、バッテリーはすぐに消耗します!バッテリーの履歴を見ると、GPSラジオが常にフルトランスミッションモードになっている!!!!に驚いた。 10分ごとに位置情報をリクエストしたこと(GPSを開いて位置情報を受信する他のインストール済みアプリはありません。

いくつかのデバイス(Moto X 2013、HTC One X、Nexus 5など)で、すべて最新のGoogle Play Services(バージョン6.1.11)およびAndroid KitKat 4.4.4

私のアプリケーションはユーザーの現在の場所に大きく依存しており、ユーザーがログインしている限り、指定された間隔で定期的に場所の更新を受信するため、バッテリーの消耗を防ぐためにPRIORITY_HIGH_ACCURACYモードを使用しません。

私の質問:

  • フュージョンロケーションプロバイダーは、PRIORITY_BALANCED_POWER_ACCURACYで更新を受信するように設定され、WI-FIまたはセルタワー情報がない場合、GPSを使用することを想定していますか?

  • もしそうなら、私は何を間違っていますか?

  • なぜこの間違った場所の更新が正しくないのですか? (「さらに大きな問題」セクションで説明したように..

  • PRIORITY_HIGH_ACCURACYパラメータを使用したときに10分間隔で開いたのではなく、常にGPS無線が開いているのはなぜですか? (ロケーションの更新をより速くトリガーする他のアプリをインストールしていません。)

26
Tal Kanel

指定された質問については、

1.は、_PRIORITY_BALANCED_POWER_ACCURACY_で更新を受信するように設定されていて、WIがない場合、GPSを使用すると想定される融合ロケーションプロバイダーです。 -FIまたはセルタワー情報?
2.もしそうなら、何が間違っているのでしょうか?

明らかに、ドキュメント内のどこにも明示的に一意のソースが指定されていないようです。いずれかのPRIORITYオプションを使用すると、コードを介しても、取得したlocationの「ソース」は「融合」されます。
[location.getProvider()戻り値: "fused"]
LocationRequest にPRIORITY_HIGH_ACCURACYがある場合にのみGPSが使用されているのを見ました。そのため、他の条件下ではGPSを使用しません。

4. PRIORITY_HIGH_ACCURACYパラメーターを使用したときにGPS無線が10分間隔で開かれるのではなく、常に開かれるのはなぜですか? (ロケーションの更新をより速くトリガーする他のアプリをインストールしていません。)

最速の間隔は1分間に設定されています。私が理解したことから、最速の間隔の値がsetIntervalの値よりも持続時間が短い場合、- setFastestIntervalsetInterval よりも優先されます。
あなたの場合、10分に対して1分。
場所の更新をトリガーする他のインストール済みアプリがないことについては、例として挙げただけで、その場合のみを明示的に指定していません。

これは、アプリケーションが位置の更新を受信する最速の速度を制御します。状況によっては(たとえば、他のアプリケーションが位置の更新をトリガーしている場合)setInterval(long)よりも速い場合があります。

したがって、起こるのは_PRIORITY_HIGH_ACCURACY_であり、GPS(排他的に)を使用して、最速の間隔セット(1分)でlocationを要求します。

3.なぜこの間違った場所の更新が正しくないのですか? (「さらに大きな問題」セクションで説明したように..

pendingIntentメカニズムのコードも確認する必要があります。注意すべきことがいくつかありますが:
location.getTime() を追加して、取得した場所の時刻を確認および検証できます。範囲内にWi-Fiセルタワーがなく、_PRIORITY_BALANCED_POWER_ACCURACY_が使用されている場合、更新されていない可能性が高いです。
「lastKnown」が呼び出されたときに使用されている、最初の場所のブロックレベルの正確さは役に立ちません。

バッテリー消費は、GPSと1分の更新の組み合わせによるものでした。実装に適している場合は、最速の間隔を5分または10分に設定してみてください。ただし、絶対に正確な場所が必要な場合は_PRIORITY_BALANCED_POWER_が役に立たない場合があります。通常、onLocationChangedで取得した場所のチェックを追加し、それに応じてLocationRequestで優先度を切り替えます。 GPSの見通し線がなく、Wi-Fiネットワークがオフになっている建物内にいる場合を除き、一般に場所を取得するのに役立ちます。

19
Pararth

AlarmManagerFusedLocationProviderを一緒に使用して、位置の更新を開始するビューでAlarmManagerが10分ごとにアラームを発動することをお勧めします。

更新された場所を取得したら、場所クライアントを切断します。 LocationRequestでインターバル時間を設定することにより、常に実行し続ける必要はありません。代わりに、AlarmManagerを使用して、各時間間隔でプロセスを呼び出すことができます。

この種のメカニズムでは、問題を解決する次の利点があります。

  • GPS無線は、最初の位置情報の更新後に切断するため、位置情報の取得中は数秒間だけ開いたままになります。したがって、GPSラジオは常に開いたままにならず、バッテリーが節約されます。
  • 古い場所などをいじることなく、10分ごとに新しい場所を取得できます。

役立つことを願っています。

4
Mehul Joisar

セルタワーは数マイルのエリアをカバーしているため、場所を取得するには最適ではありません。ロケーションを使用している場合は、ロケーションの精度を確認してください。

@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を使用します。

<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
danny117

GPS座標の更新には、GPSおよびWI-FIプロバイダーも使用できます。位置の更新には、最小距離パラメータも使用します。小さなGPSサービスの例を提供します。

回答:

1)PRIORITY_BALANCED_POWER_ACCURACY do 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;
    }
}
0
Oleg Gordiichuk