3

私は現在、5 分ごとにユーザーの位置を確認し、座標をサーバーに送信する必要があるアプリに取り組んでいます。単純な古い LocationManager API ではなく、Google Play Services の FusedLocation API を使用することにしました。主な理由は、LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY優先度レベルに気づいたからです。これは、適切なバッテリー使用量で 100 メートルの精度レベルを提供すると主張しています。私は欲しい。

私の場合、継承構造が次のアクティビティがあります。

public class MainActivity extends AppCompatActivity implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener, LocationListener

関連するコールバック (onConnected、onConnectionFailed、onConnectionSuspended、onLocationChanged) を実装します。公式ドキュメントで提案されているように、このメソッドを使用して GoogleApiClient のインスタンスも取得します。

protected synchronized GoogleApiClient buildGoogleApiClient() {
        return new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API).build();

onConnected では、次を使用して位置情報の更新を開始します

LocationServices.FusedLocationApi.requestLocationUpdates(mApiClient,
                mLocationRequest, this);

...そして onLocationChanged() で変更をキャプチャします。

ただし、しばらくすると位置情報の更新が停止するように見えることがすぐにわかりました。おそらく、このメソッドがアクティビティのライフサイクルに関連付けられているためか、わかりません。とにかく、IntentService を拡張する内部クラスを作成し、それを AlarmManager で開始することで、これを回避しようとしました。だからonConnectedで、私はこれをやった:

AlarmManager alarmMan = (AlarmManager) this
                .getSystemService(Context.ALARM_SERVICE);

        Intent updateIntent = new Intent(this, LocUpService.class);

        PendingIntent pIntent = PendingIntent.getService(this, 0, updateIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        alarmMan.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 0,
                1000 * 60 * 5, pIntent);

LocUpService クラスは次のようになります。

public static class LocUpService extends IntentService {

        public LocUpService() {
            super("LocUpService");

        }

        @Override
        protected void onHandleIntent(Intent intent) {
            Coords coords = LocationUpdater.getLastKnownLocation(mApiClient);


        }

    }

LocationUpdater は、次の静的メソッド getLastKnownLocation を含む別のクラスです。

public static Coords getLastKnownLocation(GoogleApiClient apiClient) {

        Coords coords = new Coords();
        Location location = LocationServices.FusedLocationApi
                .getLastLocation(apiClient);

        if (location != null) {

            coords.setLatitude(location.getLatitude());
            coords.setLongitude(location.getLongitude());

            Log.e("lat ", location.getLatitude() + " degrees");
            Log.e("lon ", location.getLongitude() + " degrees");

        }
        return coords;
    }

でもビックリ!! 静的メソッドへの参照を明確に渡すと、「IllegalArgumentException: GoogleApiClient パラメータが必要です」というメッセージが表示されます。これは、GoogleApiClient インスタンスがアクティビティのライフサイクルに関係しており、インスタンスをインテントサービス。

だから私は考えています:狂わずに5分ごとに定期的な位置情報の更新を取得するにはどうすればよいですか? サービスを拡張し、そのコンポーネントにすべてのインターフェイス コールバックを実装し、そこで GoogleApiClient インスタンスを構築して、バックグラウンドで実行し続ける必要がありますか? 5 分ごとに IntentService を拡張するサービスを AlarmManager に開始させて作業を実行し、関連するすべてのコールバックと GoogleApiClient を IntentService で構築する必要がありますか? 現在行っていることを続けますが、違いが生じることを期待して、GoogleApiClient をシングルトンとして構築しますか? どのようにしますか?

長くなってしまい申し訳ありません。

4

2 に答える 2

9

私は現在、5 分ごとにユーザーの位置を確認し、座標をサーバーに送信する必要があるアプリに取り組んでいます。単純な古い LocationManager API の代わりに、Google Play Services の FusedLocation API を使用することにしました

私たちのアプリにはまったく同じ要件があり、数日前にそれを実装しました。これが私が行った方法です。

起動アクティビティまたは開始したい場所で、AlarmManager を使用して LocationTracker を 5 分ごとに実行するように構成します。

private void startLocationTracker() {
    // Configure the LocationTracker's broadcast receiver to run every 5 minutes.
    Intent intent = new Intent(this, LocationTracker.class);
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(),
            LocationProvider.FIVE_MINUTES, pendingIntent);
}

LocationTracker.java

public class LocationTracker extends BroadcastReceiver {

    private PowerManager.WakeLock wakeLock;

    @Override
    public void onReceive(Context context, Intent intent) {
        PowerManager pow = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        wakeLock = pow.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
        wakeLock.acquire();

        Location currentLocation = LocationProvider.getInstance().getCurrentLocation();

        // Send new location to backend. // this will be different for you
        UserService.registerLocation(context, new Handlers.OnRegisterLocationRequestCompleteHandler() {
            @Override
            public void onSuccess() {
                Log.d("success", "UserService.RegisterLocation() succeeded");

                wakeLock.release();
            }

            @Override
            public void onFailure(int statusCode, String errorMessage) {
                Log.d("error", "UserService.RegisterLocation() failed");
                Log.d("error", errorMessage);

                wakeLock.release();
            }
        }, currentLocation);
    }
}

LocationProvider.java

public class LocationProvider {

    private static LocationProvider instance = null;
    private static Context context;

    public static final int ONE_MINUTE = 1000 * 60;
    public static final int FIVE_MINUTES = ONE_MINUTE * 5;

    private static Location currentLocation;

    private LocationProvider() {

    }

    public static LocationProvider getInstance() {
        if (instance == null) {
            instance = new LocationProvider();
        }

        return instance;
    }

    public void configureIfNeeded(Context ctx) {
        if (context == null) {
            context = ctx;
            configureLocationUpdates();
        }
    }

    private void configureLocationUpdates() {
        final LocationRequest locationRequest = createLocationRequest();
        final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
                .addApi(LocationServices.API)
                .build();

        googleApiClient.registerConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
            @Override
            public void onConnected(Bundle bundle) {
                startLocationUpdates(googleApiClient, locationRequest);
            }

            @Override
            public void onConnectionSuspended(int i) {

            }
        });
        googleApiClient.registerConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
            @Override
            public void onConnectionFailed(ConnectionResult connectionResult) {

            }
        });

        googleApiClient.connect();
    }

    private static LocationRequest createLocationRequest() {
        LocationRequest locationRequest = new LocationRequest();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(FIVE_MINUTES);
        return locationRequest;
    }

    private static void startLocationUpdates(GoogleApiClient client, LocationRequest request) {
        LocationServices.FusedLocationApi.requestLocationUpdates(client, request, new com.google.android.gms.location.LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                currentLocation = location;
            }
        });
    }

    public Location getCurrentLocation() {
        return currentLocation;
    }
}

まず、アプリケーションを拡張するクラスで LocationProvider のインスタンスを作成し、アプリの起動時にインスタンスを作成します。

MyApp.java

public class MyApp extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        LocationProvider locationProvider = LocationProvider.getInstance();
        locationProvider.configureIfNeeded(this);
    }
}

LocationProvider はシングルトンであるため、ロケーションの更新用に 1 回だけインスタンス化および構成されます。5分ごとにcurrentLocation値が更新され、必要な場所から取得できます

Location loc = LocationProvider.getInstance().getCurrentLocation();

あらゆる種類のバックグラウンド サービスを実行する必要はありません。AlarmManager は 5 分ごとに LocationTracker.onReceive() にブロードキャストし、部分的なウェイクロックにより、デバイスがスタンバイ状態であってもコードの実行が確実に終了します。これも省エネです。

次の権限が必要であることに注意してください

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

<!-- For keeping the LocationTracker alive while it is doing networking -->
<uses-permission android:name="android.permission.WAKE_LOCK" />

受信者を登録することを忘れないでください:

<receiver android:name=".LocationTracker" />
于 2015-10-06T21:19:56.177 に答える
0

アクティビティを使用して位置情報の更新を要求する最初の方法については、アクティビティの onPause() メソッドで Location Client を切断しない限り停止しないでください。そのため、アクティビティがバックグラウンド/フォアグラウンドにある限り、引き続き位置情報の更新を受け取る必要があります。ただし、アクティビティが破棄された場合、もちろん更新は取得されません。

アクティビティ ライフサイクルでロケーション クライアントを切断しているかどうかを確認します。

于 2015-10-06T21:40:29.227 に答える