FusedLocationを使ってみました。
2013年にGoogleMapを使用するための新たな手法、FusedLocationが発表されました。
このFusedLocationの最大の利点は、精度の高い位置情報を取得するために、開発者が複雑な処理を書く必要がなくなったという点です。
サンプルアプリの御紹介の前に、少しだけ概要を説明させていただきます。
すでに概要を御存知の方は飛ばしていただいて問題ございません。
FusedLocationの概要
位置情報の取得するには、以下のどちらかを利用します。
各々のメリットやデメリットも併せて簡単に記載しますので、確認してみましょう。
| メリット | デメリット | |
|---|---|---|
| GPS(衛星) | かなり正確な位置情報を取得できる。 | 屋内(屋根のある場所)では使用できない場合がある。 |
| ネットワークプロバイダ(wi-fi,3Gなど) | インターネットに接続している状態であれば、位置情報の取得が可能である。 | 取得できる位置情報の精度が低い。 |
以前の方法ではLocationManagerを使用していましたが、Mapを利用する場合は、「GPSで位置情報取得を試みて、取得できない場合は、ネットワークプロバイダで位置情報の取得を試みる」や、「取得した位置情報の精度によっては更新しない」といった、フィルタリングのようなロジックを書く必要がありました。
ところがLocationClientを用いることで、上記のようなことを開発者がそれほど意識することなく、GPSやネットワークプロバイダに加え加速度センサーなどを組み合わせることで、その状況に応じて最適な位置情報を取得することができるようになりました。
それではサンプルコードを確認していきましょう。
サンプルコード
アプリ実行図
画面レイアウトファイル(activity_main.xml)
アプリの画面レイアウトファイルです。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="15dp"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textTime"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/textLat"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/textLng"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
android:id="@+id/mapFragment1"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="15dp" />
</LinearLayout>
Activityファイル(MainActivity.java)
Activityファイルです。
継承しているのがFragmentActivityであることに注意してください。
package com.example.locationsample;
import java.text.SimpleDateFormat;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends FragmentActivity {
private GoogleMap map;
private LocationClient locationClient;
private LocationListener locationListener;
private LocationRequest locationRequest;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 第2引数と第3引数は、以降に記述するコールバックメソッド
locationClient = new LocationClient(this, connectionCallbacks, onConnectionFailedListener);
}
// LocationClient()の第2引数に指定しているコールバックメソッド
private GooglePlayServicesClient.ConnectionCallbacks connectionCallbacks = new GooglePlayServicesClient.ConnectionCallbacks() {
// GooglePlayServiceからの切断時に呼び出される
@Override
public void onDisconnected() {
Toast.makeText(MainActivity.this, "切断されました。", Toast.LENGTH_SHORT).show();
}
// GooglePlayServiceへの接続時に呼び出される
@Override
public void onConnected(Bundle bundle) {
Toast.makeText(MainActivity.this, "接続しました。", Toast.LENGTH_SHORT).show();
if (locationClient.isConnected()) {
// リスナーの登録
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (location != null) {
TextView textLat = (TextView) findViewById(R.id.textLat);
TextView textLng = (TextView) findViewById(R.id.textLng);
TextView textTime = (TextView) findViewById(R.id.textTime);
double lat = location.getLatitude();
double lng = location.getLongitude();
textTime.setText("時間:" + sdf.format(location.getTime()));
textLat.setText("緯度:" + String.valueOf(lat));
textLng.setText("経度:" + String.valueOf(lng));
LatLng latLng = new LatLng(lat, lng);
map.addMarker(new MarkerOptions().position(latLng));
map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18));
Toast.makeText(MainActivity.this, "値を更新しました。", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "値を取得できませんでした。", Toast.LENGTH_SHORT).show();
}
}
};
// LocationRequestの生成と各種処理(定期的に位置情報を取得するため)
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(50000);// LocationRequestの時間間隔をミリ秒単位で指定
locationClient.requestLocationUpdates(locationRequest, locationListener);
} else {
Toast.makeText(MainActivity.this, "接続されていません", Toast.LENGTH_SHORT).show();
}
}
};
// LocationClient()の第3引数に指定しているコールバックメソッド
private GooglePlayServicesClient.OnConnectionFailedListener onConnectionFailedListener = new GooglePlayServicesClient.OnConnectionFailedListener() {
// GooglePlayServiceへの接続に失敗した際に呼び出される
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(MainActivity.this, "接続に失敗しました。", Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onResume() {
super.onResume();
FragmentManager fm = getSupportFragmentManager();
SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentById(R.id.mapFragment1);
map = mapFragment.getMap();
Toast.makeText(MainActivity.this, "接続を開始します。", Toast.LENGTH_SHORT).show();
locationClient.connect();// GooglePlayServiceへの接続
}
@Override
protected void onPause() {
super.onPause();
locationClient.removeLocationUpdates(locationListener);// リスナーの解除
locationClient.disconnect();// GooglePlayServiceからの切断
map.clear();
}
}
