web-dev-qa-db-ja.com

Android-複数のアクティビティにLocationListenerを実装する最良の方法

私はかなり長い間この問題に悩まされてきました。私はいくつかの異なるアクティビティで非常に広範囲に位置情報を使用するアプリに取り組んでいます。私が見つけたすべての例は、すべてのアクティビティで個別のLocationListenerを使用しています。これは私の状況では現実的ではありません。

複数のアクティビティにわたってユーザーの位置を追跡する最も効率的な方法は何だろうと思っています。現在、LocationListenerを実装し、ブロードキャストを使用してActivity基本クラスの静的なlatおよびlongフィールドを更新するサービスを作成しました。これは、サービスが常に実行されていることを意味し、理想的ではありません。しかし、必要なときにだけサービスをシャットダウンして再起動すると、適切な場所を取得するのに時間がかかります。アクティビティのonCreate()に位置データが必要です。アクティビティ基本クラスに実装しようとしても同じです。 onResume/onCreateでリスナーを常に登録し、onPause()で登録を解除すると、更新の受信を開始するのに時間がかかりすぎます。また、バインドできるサービスを作成しようとしたため、場所が必要なときにのみ開始されます。しかし、私は同じ問題を抱えています。サービスにバインドして更新を取得するのに時間がかかりすぎます。

現在使用しているサービスは機能しますが、これまで読んだすべてのことから、このような些細なことのために常に実行しているサービスを使用するべきではありません。しかし、アプリの全体的なポイントは、ユーザーの現在の場所に基づいて関連データを提供することです。そのため、バックグラウンドで実行され、定期的に更新を提供するサービスがあります。この時点でデザインを再検討した大きな問題の1つは、ユーザーがGPSをオンにせずにアプリを起動してから有効にすると、onProviderEnabled()が呼び出されないことを最近発見したことです。このシナリオでは、アプリはGPSが有効になっていることを認識できないため、更新のリッスンを開始できます。

LocationManagerとLocationListenerを例を見れば理解できたと思いましたが、複数のアクティビティで位置データが必要なこの状況にそれを適用することはできないようです。どんな助けやアドバイスも大歓迎です。

40
d370urn3ur

私が通常この要件を実装する方法は、SDKドキュメントの Local Service Sample にあるようなバインドされたサービス実装を使用することです。明らかに、すべてのロケーションコードを1回だけ作成できるサービスの利点に精通しています。

バインディングを介してサービスにアクセスすると、アプリケーションがフォアグラウンドにないときに実行されなくなるため、サービス自体を開始および停止できます(アクティビティがバインドされなくなるとすぐに終了します)。この機能をうまく機能させるためのキーであるIMOは、onStart()でサービスをバインドし、onStop()でUNBINDをバインドすることです。最初のものが停止する前に開始されます)。これにより、アプリ内を移動するときにサービスが停止するのを防ぎ、アプリケーション全体(または少なくとも場所に関心のある部分)がフォアグラウンドを離れたときにのみサービスを停止できます。

バインディングでは、アクティビティがサービスのメソッドを直接呼び出して最新の位置を取得できるため、ブロードキャストで位置データを渡す必要はありません。ただし、ブロードキャストは、新しい更新が利用可能であることを示す方法としてはまだ有利です...しかし、これは、サービスのgetLocation()メソッドを呼び出すリスニングアクティビティの通知者になります。

私の0.02ドル。お役に立てば幸いです!

43
Devunwired

私は同じ問題を抱えており、Devunwiredの良い答えでそれを解決しようとしましたが、いくつかの問題がありました。サービスを停止する方法を見つけることができず、アプリを終了したときにGPSモジュールがまだ実行されていました。だから私は別の方法を見つけました:

GPS.Javaクラスを作成しました。

public class GPS {

    private IGPSActivity main;

    // Helper for GPS-Position
    private LocationListener mlocListener;
    private LocationManager mlocManager;

    private boolean isRunning;

    public GPS(IGPSActivity main) {
        this.main = main;

        // GPS Position
        mlocManager = (LocationManager) ((Activity) this.main).getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();
        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        // GPS Position END
        this.isRunning = true;
    }

    public void stopGPS() {
        if(isRunning) {
            mlocManager.removeUpdates(mlocListener);
            this.isRunning = false;
        }
    }

    public void resumeGPS() {
        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        this.isRunning = true;
    }

    public boolean isRunning() {
        return this.isRunning;
    }

    public class MyLocationListener implements LocationListener {

        private final String TAG = MyLocationListener.class.getSimpleName();

        @Override
        public void onLocationChanged(Location loc) {
            GPS.this.main.locationChanged(loc.getLongitude(), loc.getLatitude());
        }

        @Override
        public void onProviderDisabled(String provider) {
            GPS.this.main.displayGPSSettingsDialog();
        }

        @Override
        public void onProviderEnabled(String provider) {

        }

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

        }

    }

}

このクラスは、GPS座標を必要とするすべてのアクティビティで使用されます。すべてのアクティビティは、次のインターフェイスを実装する必要があります(通信に必要):

public interface IGPSActivity {
    public void locationChanged(double longitude, double latitude);
    public void displayGPSSettingsDialog();
}

これで、私のメインアクティビティは次のようになります。

public class MainActivity extends Activity implements IGPSActivity {

    private GPS gps;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        gps = new GPS(this);
    }


    @Override
    protected void onResume() { 
        if(!gps.isRunning()) gps.resumeGPS();   
        super.onResume();
    }

    @Override
    protected void onStop() {
        gps.stopGPS();
        super.onStop();
    }


    public void locationChanged(double longitude, double latitude) {
        Log.d(TAG, "Main-Longitude: " + longitude);
        Log.d(TAG, "Main-Latitude: " + latitude);
    }


    @Override
    public void displayGPSSettingsDialog() {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(intent);
    }
}

そしてそのような2番目のもの:

public class TEST4GPS extends Activity implements IGPSActivity{

    private GPS gps;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.gps = new GPS(this);
    }

    @Override
    public void locationChanged(double longitude, double latitude) {
        Log.d("TEST", "Test-Longitude: " + longitude);
        Log.d("TEST", "Test-Latitude: " + latitude);

    }

    @Override
    protected void onResume() { 
        if(!gps.isRunning()) gps.resumeGPS();   
        super. onResume();
    }

    @Override
    protected void onStop() {
        gps.stopGPS();
        super.onStop();
    }

    @Override
    public void displayGPSSettingsDialog() {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(intent);

    }
}

Devunwiredのソリューションほど美しくはありませんが、私にとってはうまくいきます。チャ

17
Spipau

サービスが変更時にlatiteとlongの座標をsqlite dbに書き込むようにすることで、サービスバインディングのオーバーヘッドがなく、すべてのアクティビティで座標にアクセスできます。

おそらく、メインアクティビティでGPSステータスを確認できます。GPSがオフになっている場合は、ユーザーに有効にするように促すことができます。 GPSが有効になったら、サービスを開始します。

0
travega