10

5 分ごとに携帯電話の現在の位置を (無料で利用可能なすべての位置情報プロバイダーを使用して) 決定し、それをサーバーに送信するアプリを作成する必要があります。

アプリケーションの開始時には位置情報プロバイダーが機能せず、後で利用可能になった場合、アプリケーションはその位置データも処理する必要があります。

これを行うために、次のクラスを実装しました。私のアクティビティの 1 つで、そのインスタンスを作成し、そのstartTrackingUpdatesメソッドを呼び出します。locationChangeHandler位置データの処理を行います。

public class LocationTracker implements ILocationTracker, LocationListener {
    public static final long MIN_TIME_BETWEEN_UPDATES = 1000 * 60 * 5; // 5 minutes
    public static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
    private ILocationManager locationManager;
    private ILocationChangeHandler locationChangeHandler;

    public LocationTracker(final ILocationManager aLocationManager,
            final ILocationChangeHandler aLocationChangeHandler) {
        this.locationManager = aLocationManager;
        this.locationChangeHandler = aLocationChangeHandler;
    }

    public void startTrackingUpdates() {
        final List<String> providers = locationManager.getAllProviders();

        for (final String curProviderName : providers)
        {
            final ILocationProvider provider = locationManager.getLocationProvider(curProviderName);

            if (!provider.hasMonetaryCost())
            {
                subscribeToLocationChanges(provider);
            }
        }
    }

    private void subscribeToLocationChanges(final ILocationProvider aProvider) {
        locationManager.requestLocationUpdates(aProvider.getName(), MIN_TIME_BETWEEN_UPDATES, 
                (float)MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
    }

    public void onLocationChanged(final Location aLocation) {
        locationChangeHandler.processLocationChange(new LocationWrapper(aLocation));
    }

    public void onProviderDisabled(final String aProvider) {
    }

    public void onProviderEnabled(final String aProvider) {
    }

    public void onStatusChanged(final String aProvider, final int aStatus, 
            final Bundle aExtras) {
    }
}

アプリケーションを作成し、携帯電話にインストールしました。それから、朝、携帯電話を持って仕事に行き、家に帰りました。自宅でアプリケーションの 1 日にわたる作業の結果を確認したところ、データベースに 1 つのレコードしか見つかりませんでした。

システムの残りの部分 (サーバーへの位置データの送信、データベースへの保存) が正しく機能していれば、位置追跡コードに何らかの問題があるはずです (onLocationChanged位置を数回変更したにもかかわらず、呼び出されませんでした)。

私のコードの何が問題なのですか (ロカチン プロバイダーの 1 つに従ってonLocationChanged、電話の位置がメートル以上変化するたびに が呼び出されるようにするには、どのように変更すればよいですか) ?MIN_DISTANCE_CHANGE_FOR_UPDATES

更新 1 (18.08.2013 13:59 MSK):

msh の推奨に従ってコードを変更しました。次のコードを使用してタイマーを開始します。

public void startSavingGeoData() {
    final IAlarmManager alarmManager = activity.getAlarmManager();
    final IPendingIntent pendingIntent = activity.createPendingResult(
            ALARM_ID, intentFactory.createEmptyIntent(), 0);
    alarmManager.setRepeating(INTERVAL, pendingIntent);
}

activity私は次のタイマーイベントハンドラーを入れました:

@Override
protected void onActivityResult(final int aRequestCode, final int aResultCode, 
        final Intent aData) {
    geoDataSender.processOnActivityResult(aRequestCode, aResultCode, 
            new IntentWrapper(aData));
}

電話がオンになると、すべてが期待どおりに機能し、ミリ秒単位onActivityResultで実行されます。INTERVAL

しかし、電源ボタンを押すと(画面が無効になります)、onActivityResultまったく呼び出されません。電源ボタンをもう一度押すと、電話の電源を切ってから経過したonActivityResult回数だけ実行されます。数ミリ秒間INTERVAL電話をオフにすると、1 回起動します。電話をミリ秒1 * INTERVALオフにすると、2回起動します。2 * INTERVAL

注: 「電源を切る」とは、電源ボタンを短く押すことを意味します (たとえば、電話は引き続き「動作」し、着信 SMS に反応します)。

電話がスリープ状態であってもstartSavingGeoData、メソッドがミリ秒onActivityResultごとに実行されるようにするには、コードをどのように変更すればよいですか?INTERVAL

更新 2 (18.08.2013 19:29 MSK):どちらalarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 0, INTERVAL, pendingIntent)alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, INTERVAL, INTERVAL, pendingIntent)問題を解決しませんでした。

4

1 に答える 1

8

あなたのコードはおそらく正しいですが、携帯電話がスリープ状態のときはロケーション プロバイダーが実行されていません。ウェイクロックを取得する必要があるかもしれません (消費電力を気にしない場合)、または AlarmManager を使用してアプリケーションをスケジュールし、定期的にウェイクアップして位置を確認する必要があります (更新を待っている間もアクティブなウェイクロックが必要です。 AlamManager によって取得されるか、独自のもの)。

于 2013-08-15T20:34:36.907 に答える