web-dev-qa-db-ja.com

Android:requestLocationUpdatesは最大45秒ごとに位置を更新します

バックグラウンド

私はAndroidアプリを主な機能としてユーザーの位置を追跡し、ユーザーがどこかのポイントに近づいたときにアラートを出すことを書いています。したがって、ユーザーの位置を定期的に更新する必要があります。これらの間隔ユーザーがターゲットに近づくにつれて小さくなります。つまり、ユーザーがターゲットから1 km以内にいる場合は、ユーザーが到着するまで、20秒ごとなどに位置を更新します。

問題

(_provider = LocationManager.NETWORK_PROVIDER_)をテストするとき、_minTime < 45000_を使用したrequestLocationUpdates(provider, minTime, minDistance, locationListener)の呼び出しは、_minTime = 45000_と同じ効果があります。つまり、間隔が-の更新を取得します正確に 45秒。
最小時間パラメーターは「ヒント」にすぎないことはわかっていますが、私のアプリではヒントとして使用されていません。間隔が45秒未満になるまで、指定された間隔で更新を取得します。場所の更新の最小間隔が45秒でAndroidにハードコードされているように見えますが、これはちょっと変わっています。加えて、私はこの問題について以前に聞いたことがなく、ここStackoverflowで対処されている問題を見つけることができませんでした。

頻繁に更新を取得することができないため、私の回避策(今のところ)は、新しい場所が必要なときはいつでも手動でrequestLocationUpdatesを呼び出し、次に利用可能な最初の場所を使用することです。これを短い間隔で行うには、handler.postDelayed(myRunnable, updateInterval)を使用して呼び出しを遅延させ、myRunnablerequestLocationUpdatesの呼び出しを処理します。ただし、この方法は、時間の約50%(明らかにランダム)しか機能しません。

誰かが問題を知っていますか?それを修正する方法はありますか?または、_minTime = 0_を設定して、最高のものを期待する唯一のオプションですか?

ソースコード

MyRunnableのソースコードは次のとおりです。そのrun()メソッドは、handler.postDelayed(myRunnable, updateInterval)を使用して手動で定期的に呼び出します。

_public class MyRunnable implements Runnable {
    private LocationManager manager;
    private LocationListener listener;

    @Override
    public void run() {
        // This is called everytime a new update is requested
        // so that only one request is running at a time.
        removeUpdates();

        manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        listener = new LocationListener() {
            @Override
            public void onLocationChanged(Location loc) {
                location = loc;
                latitude = loc.getLatitude();
                longitude = loc.getLongitude();
                accuracy = Math.round(loc.getAccuracy());

                handler.sendMessage(Message.obtain(handler, KEY_MESSAGE_LOCATION_CHANGED));

                checkForArrival();
            }

            // Other overrides are empty.
        };

        if(!arrived)
            manager.requestLocationUpdates(provider, updateInterval, 0, listener);
    }

    /**
     * Removes location updates from the LocationListener.
     */
    public void removeUpdates() {
        if(!(manager == null || listener == null))
            manager.removeUpdates(listener);
    }

    // Another method for "cleaning up" when the user has arrived.
}
_


そして、これが私のhandlerです。

_handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
            case KEY_MESSAGE_LOCATION_CHANGED:
                if(myRunnable != null) {
                    myRunnable.removeUpdates();
                    handler.postDelayed(myRunnable, updateInterval);
                }
                break;
            }
        }
    };
_


追加情報

位置情報更新の全体がサービスで実行されます。

私は何度かドキュメントを読んだことがあり、Googleが問題を解決し、他にもさまざまな回避策を試しました。なにもしません。

私はこのことからログアウトしました、そして見るべき唯一のエキサイティングなことは私の頻繁な位置要求への大きな脂肪「無視」です。すべての適切なメソッドが呼び出されます。

どんな助けでも非常に感謝します!

23
stemadsen

MinTimeは任意の値に設定できます。ただし、新しい場所が利用可能になったときにのみ更新を取得します。ネットワークは、私が所有するすべての電話で約45秒ごとにのみ更新されます。これは、ネットワークプロバイダーの制限のようです。より頻繁な更新が必要な場合は、GPSプロバイダーを使用してください。 GPSハードウェアによっては、最大更新レートが約4Hzになるはずです。

8
Frohnzie

あなたは完全に正しい、最小時間45秒はAndroidでハーコード化されています。

これは、AndroidコアにまだあったときのNetworkLocationProviderクラスのソースコードのようです。

http://www.netmite.com/Android/mydroid/frameworks/base/location/Java/com/Android/internal/location/NetworkLocationProvider.Java

変数を見てください。

private static final long MIN_TIME_BETWEEN_WIFI_REPORTS = 45 * 1000; // 45 seconds

そして方法:

@Override
public void setMinTime(long minTime) {
    if (minTime < MIN_TIME_BETWEEN_WIFI_REPORTS) {
        mWifiScanFrequency = MIN_TIME_BETWEEN_WIFI_REPORTS;
    } else {
        mWifiScanFrequency = minTime;
    }
    super.setMinTime(minTime);
}

現在、NetworkLocationProviderはAndroidコアの外にあります。/system/appのNetworkLocation.apkにあります。

がコアから外れている理由の説明は、次の場所にあります。

https://groups.google.com/forum/?fromgroups=#!topic/Android-platform/10Yr0r2myGA

しかし、45秒の最小時間がまだあるようです。このNetworkProviderの逆コンパイルを見てください。

http://Android.fjfalcon.com/xt720/miui-trans/apk-decompiled/NetworkLocation/smali/com/google/Android/location/NetworkLocationProvider.smali

.line 149
const-wide/32 v4, 0xafc8

iput-wide v4, p0, Lcom/google/Android/location/NetworkLocationProvider;->mWifiScanFrequency:J

ご想像のとおり、0xafc8を10進数に変換すると、45000ミリ秒になります。

なぜ45秒なのか説明がありません。サービスの過負荷や他のユーザーが望まない使用を回避するなどの理由があると思います。

実際、Geolocation APIには100リクエストの礼儀的制限があります。

https://developers.google.com/maps/documentation/business/geolocation/#usage_limits

ただし、Googleマップアプリではこのルールを尊重していないようです。それを開いて、ネットワークの場所のみをアクティブにすると、現在地が45秒よりもはるかに頻繁に更新されることがわかります。

Googleマップが開いているときに、この行がlogcatで不審に頻繁(1秒に33回)になっていることに気付きました。

02-20 20:12:08.204:V/LocationManagerService(1733):getAllProviders

GoogleマップもremoveUpdates()とrequestLocationUpdates()を再度呼び出して、新しい位置を取得していると思います。

だから私は修正はないと思います、そしてこれはあなたが45秒で1つ以上のネットワークの場所を取得したい場合にできる最善の方法です。

18
djpeinado

私は同様の問題を抱えていました。 locationManager.requestSingleUpdate()の最後にonLocationChanged()を呼び出したところ、更新が強制的に実行されました。遅延コマンドを設定してからrequestSingleUpdateを実行し、含まれているlocationListenerを登録してください。

私はGPS時計を作成しようとしましたが、更新は1〜5秒程度のどこかで更新に一貫性がありませんでした。ただし、別のアプリケーションで機能する場合があります。

0
rznazn