Xamarin で android の GPS NMEA メッセージを取得する
Xamarin で android の GPS 位置情報を利用 に少しコードを追加して、GPS の NMEA メッセージを取得してみました。
これをテキストファイルに保存するだけで、地図ソフトなんかで読み込める GPS のログファイルになります。フォーマットを変換して google アースで軌跡を表示させたりもできます。
まず、Xamarin で AndroidManifest.xml が見当たらないんだけど、どうするの? なんかを参考に、GPS のパーミッションを設定します。(ACCESS_FINE_LOCATION を許可)
アクティビティは、文字を表示するために TextView を 3個貼り付けています。NMEA メッセージを表示する TextView はスクロールさせたかったので、ScrollView の上に貼り付けました。
以下コード
実行してみた様子
位置情報が更新されなくても(有効な位置情報が無くても)時間のデータは更新されて、OnNmeaReceived イベントが発生するので、データを利用するときには注意する。OnLocationChanged イベントは有効な位置情報が得られてから発生するので、それを利用するとか、NMEA データの内容を解釈して判断するとか。
(この写真、位置データを取得する前の写真だった。ちょっと失敗。)
これをテキストファイルに保存するだけで、地図ソフトなんかで読み込める GPS のログファイルになります。フォーマットを変換して google アースで軌跡を表示させたりもできます。
まず、Xamarin で AndroidManifest.xml が見当たらないんだけど、どうするの? なんかを参考に、GPS のパーミッションを設定します。(ACCESS_FINE_LOCATION を許可)
アクティビティは、文字を表示するために TextView を 3個貼り付けています。NMEA メッセージを表示する TextView はスクロールさせたかったので、ScrollView の上に貼り付けました。
以下コード
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Locations; // GPSを使うので追加
using System.Linq; // クエリの処理に必要
namespace gps_nmea0316
{
[Activity (Label = "gps_nmea0316", MainLauncher = true)]
public class Activity1 : Activity, ILocationListener, GpsStatus.INmeaListener
{
private LocationManager _locationManager;
private TextView text1;
private TextView text2;
private TextView text3;
private string _locationProvider;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
text1 = FindViewById<TextView> (Resource.Id.textView1);
text2 = FindViewById<TextView> (Resource.Id.textView2);
text3 = FindViewById<TextView> (Resource.Id.textView3);
InitializeLocationManager(); // GPS を使う準備(すぐ下)
}
// GPSを使う準備
private void InitializeLocationManager()
{
_locationManager = (LocationManager) GetSystemService(LocationService);
var criteriaForLocationService = new Criteria
{
Accuracy = Accuracy.Fine
// Fine なら GPS 、Coarse なら ネットワークを使用して測位
};
_locationManager.AddNmeaListener (this);
// criteriaForLocationService(すぐ上)を使いたいな とおねがい
var acceptableLocationProviders
= _locationManager.GetProviders(criteriaForLocationService, true);
// ロケーションプロバイダが使えるかな?
if (acceptableLocationProviders.Any())
{
// acceptableLocationProvidersに何かクエリが入っていたら
// 最初のクエリを取り出す
_locationProvider = acceptableLocationProviders.First();
}
else
{
// ロケーションプロバイダが使えないみたい
_locationProvider = String.Empty;
text1.Text="測位サービスが使えないみたい";
}
}
protected override void OnResume()
{
base.OnResume();
// アクティビティがレジュームされたら
// 位置情報を更新してくれるように依頼する
_locationManager.RequestLocationUpdates(_locationProvider, 0, 0, this);
text1.Text = _locationProvider.ToUpper () + " 位置情報更新待ち";
}
protected override void OnPause()
{
base.OnPause();
// アクティビティが停止されたら
// 位置情報更新しないように依頼
_locationManager.RemoveUpdates(this);
_locationManager.RemoveNmeaListener (this);
}
// 位置情報が更新された時の処理
public void OnLocationChanged(Location location)
{
// 何もしない
}
// ロケーションプロバイダが有効になった時の処理
public void OnProviderEnabled(string provider)
{
// 何もしない
}
// ロケーションプロバイダが無効になった時の処理
public void OnProviderDisabled(string provider)
{
// 何もしない
}
// ロケーションプロバイダのステータスが変わった時の処理
public void OnStatusChanged(string provider, Availability status, Bundle extras)
{
// 表示してみる
text1.Text=string.Format("{0}, {1}", provider, status);
}
// NMEA メッセージを受信した時の処理
public void OnNmeaReceived(long time,string nmea)
{
// 表示する
text1.Text=_locationProvider.ToUpper () + " 測位中";
text2.Text = "TIME: " + time.ToString ();
text3.Text = text3.Text.Insert (0, nmea);
// 2000文字を超えた分を削除する
// (メモリ節約)
if (2000 < text3.Text.Length) {
text3.Text.Remove(2000);
}
}
}
}
実行してみた様子
位置情報が更新されなくても(有効な位置情報が無くても)時間のデータは更新されて、OnNmeaReceived イベントが発生するので、データを利用するときには注意する。OnLocationChanged イベントは有効な位置情報が得られてから発生するので、それを利用するとか、NMEA データの内容を解釈して判断するとか。
(この写真、位置データを取得する前の写真だった。ちょっと失敗。)