A Day In The Life

とあるプログラマの備忘録

Android で GPS 衛星からの情報を NMEA 形式で取得する方法

Android 2.0 から GpsStatus.NmeaListener というリスナが追加されました。このリスナは NMEA-0183という形式で GPS 衛星の情報を取得できます。このリスナかなり細かい情報がとれて面白いのでデータを取得するプログラムを作成してみました。
なお NMEA のデータ形式については以下のサイトが詳しいのでこちらをご覧ください。

プログラム

画面イメージ

アプリの画面イメージ

初期化処理

GpsStatus.NmeaListener リスナを追加します。このリスナを追加して LocationManager#requestLocationUpdates すると1秒おきに onNmeaReceived メソッドが呼びだされます。
※addNmeaListener するだけでは onNmeaReceived メソッドが呼び出されないので注意してください。

public class LocationCheckerActivity extends Activity
    implements LocationListener, GpsStatus.NmeaListener {
  private LocationManager locationManager;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
    locationManager.addNmeaListener(this);
    // requestLocationUpdatesと連動して動きます。
    LocationProvider p = locationManager.getProvider("gps");
    locationManager.requestLocationUpdates(p.getName(), 0, 0, this);
  }
  :
}
終了処理

リスナを削除します。

  @Override
  protected void onDestroy() {
    super.onDestroy();
    locationManager.removeUpdates(this);
    locationManager.removeNmeaListener(this);
  }
GPS 衛星の情報を表示する

実際に実機(SoftbankのDesire)で取得できたデータは GPGSV,GPGSA,GPRMC,GPVTG,GPGGA の5種類でした。なお GPGSV は1データで4機の衛星データが取得できます。4機以上のデータが取れる場合は分割して送られてきます。

  // LocationListenerの処理は割愛します。
  @Override
  public void onNmeaReceived(long timestamp, String nmea) {
    String[] data = nmea.split(",");
    // GPGSV,GPGSA,GPRMC,GPVTG,GPGGA
    if (data[0].equals("$GPGSA")) {
      TextView tv = (TextView)findViewById(R.id.nmea_gpgsa);
      tv.setText(nmea.trim());
    } else if (data[0].equals("$GPRMC")) {
      TextView tv = (TextView)findViewById(R.id.nmea_gprmc);
      tv.setText(nmea.trim());
    } else if (data[0].equals("$GPVTG")) {
      TextView tv = (TextView)findViewById(R.id.nmea_gpvtg);
      tv.setText(nmea.trim());
    } else if (data[0].equals("$GPGGA")) {
      TextView tv = (TextView)findViewById(R.id.nmea_gpgga);
      tv.setText(nmea.trim());
    } else if (data[0].equals("$GPGSV")) {
      LinearLayout layout = (LinearLayout)findViewById(R.id.nmea_gpgsv_layout);
      // データ件数を取得
      int messageNum = Integer.valueOf(data[2]);
      TextView tv = (TextView)layout.findViewById(messageNum);
      if (tv == null) {
        tv = new TextView(this);
        layout.addView(tv);
        tv.setId(messageNum);
      }
      tv.setText(nmea.trim());
    }
  }

ちなみに NMEA は National Marine Electronics Association の略らしいです。