AndroidでLocationManagerを使って位置情報を取得する方法を紹介します。現在、minSdkVersion
が19で開発しています。
事前情報
API 19ではFragment#requestPermissions
とFragment#onRequestPermissionsResult
が使えない*1ので、一旦パーミッションの許可をFragmentを持っているActivityで受け取ってから再度Fragmentで処理させます。
public class FragmentBase extends Fragment { public void onFragmentRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { } }
MapFragment
public class MapFragment extends FragmentBase implements LocationListener { private static final int REQUEST_LOCATION_PERMISSION = 101; private LocationManager locationManager = null; //30秒に1度更新する private final int LOCATION_UPDATE_MIN_TIME = 30 * 1000; //10m移動する度に更新する private final int LOCATION_UPDATE_MIN_DISTANCE = 10; //(ここに後述するコードを追加していく) }
Switchをオンオフすると位置測位を開始します。
@Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { gpsSwitch.setOnCheckedChangeListener((compoundButton, b) -> { if (b) { //スイッチをオンにした! //GPSが許可されているかどうか確認する if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { //パーミッションの許可を取得する ActivityCompat.requestPermissions(getActivity(), new String[]{ Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION }, REQUEST_LOCATION_PERMISSION); } else { //すでにGPSが許可されている場合は測位を開始する startLocation(); } } else { //スイッチをオフにした! stopLocation(); } }); return view; }
パーミッションの許可をもらったときの処理。
@Override public void onFragmentRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onFragmentRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_LOCATION_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 使用が許可された startLocation(); } else { //強制的にオフにする gpsSwitch.setChecked(false); } }
位置測位を開始する。
補足すると、室内の場合に位置測位プロバイダがgpsだとほとんどonStatusChangedイベントが発生しない。networkにすると頻繁にイベントが発生するようになる。
private void startLocation() { if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationManager = (LocationManager) getActivity().getSystemService(Activity.LOCATION_SERVICE); //位置測位プロバイダを決定する Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); criteria.setPowerRequirement(Criteria.POWER_MEDIUM); criteria.setBearingRequired(false); criteria.setSpeedRequired(false); criteria.setAltitudeRequired(false); String bestProvider = locationManager.getBestProvider(criteria, true); //測位を開始する locationManager.requestLocationUpdates(bestProvider, LOCATION_UPDATE_MIN_TIME, LOCATION_UPDATE_MIN_DISTANCE, this); } }
位置測位を終了する。
private void stopLocation() { if (locationManager != null) { locationManager.removeUpdates(this); } locationManager = null; }
LocationListenerの実装。
@Override public void onLocationChanged(Location location) { final float longitude = Double.valueOf(location.getLongitude()).floatValue(); final float latitude = Double.valueOf(location.getLatitude()).floatValue();; Log.e("MapFragment", String.format("lon:%f lat:%f", longitude, latitude)); } @Override public void onStatusChanged(String s, int i, Bundle bundle) { switch (i) { case LocationProvider.AVAILABLE: Log.e("MapFragment", "LocationProvider.AVAILABLE"); break; case LocationProvider.OUT_OF_SERVICE: Log.e("MapFragment", "LocationProvider.OUT_OF_SERVICE"); break; case LocationProvider.TEMPORARILY_UNAVAILABLE: Log.e("MapFragment", "LocationProvider.TEMPORARILY_UNAVAILABLE"); break; } } @Override public void onProviderEnabled(String s) { } @Override public void onProviderDisabled(String s) { }
*1:API 23以降でFragmentからパーミッションの許可を得ることができるようになった