Taizoo's Tech note

技術系の備忘録

FusedLocationProviderClientで取得した現在位置をGoogleMapに表示する

前回は、アプリにGoogleMapを表示するところまでやってみました。
今回は、Google Play ServiceのFusedLocationProviderClientを使って、GoogleMapに現在位置を表示します。

目次

ソースコード

/**
 * MapsActivityクラス
 */
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    private ActivityMapsBinding binding;
    private Marker marker;
    private FusedLocationProviderClient flpClient = null;
    private LocationCallback locationCallback = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMapsBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        // 位置情報が変更された際に、通知を受け取るコールバックメソッドを定義
        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(@NonNull LocationResult locationResult) {
                super.onLocationResult(locationResult);
                Location location = locationResult.getLastLocation();
                LatLng latlng = new LatLng(location.getLatitude(), location.getLongitude());
                marker.setPosition(latlng);
                mMap.moveCamera(CameraUpdateFactory.newLatLng(latlng));
            }
        };
    }

    @Override
    protected void onResume() {
        super.onResume();
        startPositioning();
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopPositioning();
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        LatLng sydney = new LatLng(-34, 151);
        marker = mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (1 != requestCode) {
            return;
        }

        // ユーザが許可してくれた場合は、位置情報の取得を開始する
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            startPositioning();
        } else {
            Toast.makeText(this, "Permission Error.", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 位置情報の取得を開始する。
     */
    private void startPositioning() {

        // 位置情報へのアクセス許可チェック
        if (!checkPermission()) {
            return;
        }

        // 位置情報の取得を開始する
        flpClient = LocationServices.getFusedLocationProviderClient(this);
        LocationRequest request = LocationRequest.create();
        request.setInterval(1000);
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        // 位置情報が変更された際は、locationCallbackで受け取る
        flpClient.requestLocationUpdates(request, locationCallback, null);
    }

    /**
     * 位置情報の取得を停止する。
     */
    private void stopPositioning() {
        if (null != flpClient) {
            flpClient.removeLocationUpdates(locationCallback);
        }
    }

    /**
     * 位置情報へのアクセスが許可されているかチェックする。<br>
     * 許可されていてない場合、パーミッションリクエストを行う。
     * @return ture:許可 / false:未許可
     */
    private boolean checkPermission() {
        // アクセス許可チェック
        if (checkSelfPermission(ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            return true;
        }

        // パーミッションリクエスト
        requestPermissions(new String[] {ACCESS_FINE_LOCATION},1);
        return false;
    }
}

ソースのざっくり解説

  1. onCreate()で位置情報を受け取るLocationCallbackを定義
  2. onResume()で位置情報の更新を開始(startPositioning()呼び出し)
  3. onStop()で位置情報の更新を停止
  4. startPostioning()で
    1. 位置情報のパーミッションチェック
    2. 未許可の場合はパーミッションリクエス
    3. 許可の場合は、FusedLocationProviderClientを使って、位置情報の更新を開始
  5. onRequestPermissionsResult()でパーミッションリクエストの結果を処理
    1. 許可されていれば再度startPositioning()呼び出し
  6. 位置情報が更新されると、1 で定義したLocationCallbackのonLocationResult()が呼ばれて、マップとアイコンを更新 という感じです。

今回のポイント

パーミッションをチェック&リクエストする

今回の本題ではありませんが、端末の位置情報にアクセスするためには、ユーザに位置情報へのアクセスを許可してもらう必要があります。 やることは2つです。

  1. AndroidManifest.xmlパーミッションの記載を追加
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  2. ユーザにパーミッションリクエストを行う
    パーミッションチェックを行っていない状態で、FusedLocationProviderClientを使って位置情報の更新を開始しようとするとエラーになります。
    そこで、checkPermission()を呼び出し、位置情報へのアクセスの許可状態のチェックと許可されていない場合は、リクエストを行います。
    f:id:Taizoo:20220122150054p:plain:w300
    ユーザの選択結果をonRequestPermissionsResult()で受け取り処理しています。

FusedLocationProviderClientを使って位置情報の更新をリクエストする

private void startPositioning() {

    // 位置情報へのアクセス許可チェック
    if (!checkPermission()) {
        return;
    }

    // 位置情報のリクエストを生成する
    LocationRequest request = LocationRequest.create();
    request.setInterval(1000);
    request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    // 位置情報の更新をリクエストする
    flpClient = LocationServices.getFusedLocationProviderClient(this);
    flpClient.requestLocationUpdates(request, locationCallback, null);
}
  • FusedLocationProviderClientを使うためには、GooglePlayServiceのLocationAPIを使用します。
    LocationAPIを使用するためには、build.gradle(:app)に以下を追加します。
implementation 'com.google.android.gms:play-services-location:19.0.1'
  • [LocationServices].getFusedLocationProviderClient()でFusedLocationProviderClientインスタンスを取得します。
  • requestLocationUpdates()で位置情報の更新を要求します。
  • 位置情報が更新されると、onLocationResult()が呼び出されます。

取得した現在位置でマップの中心座標とアイコンの座標を変更する

locationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(@NonNull LocationResult locationResult) {
        super.onLocationResult(locationResult);
        Location location = locationResult.getLastLocation();
        LatLng latlng = new LatLng(location.getLatitude(), location.getLongitude());
        marker.setPosition(latlng);
        mMap.moveCamera(CameraUpdateFactory.newLatLng(latlng));
    }
};
  • onLocationResult()でLocationResultを受け取ることができます。
  • 受け取ったLocationResultから緯度経度を取得し、LatLngオブジェクトを生成します。
  • 生成したLatLngオブジェクトを、マーカーの座標とマップの中心座標にセットします。

実行結果

実行するとこのように現在位置が表示されます。
f:id:Taizoo:20220122152741p:plain:w300

リファレンス

LatLng  |  Google Play services  |  Google Developers
LocationServices  |  Google Play services  |  Google Developers
LocationResult  |  Google Play services  |  Google Developers
LocationRequest  |  Google Play services  |  Google Developers
LocationCallback  |  Google Play services  |  Google Developers
FusedLocationProviderClient  |  Google Play services  |  Google Developers