特集:.NETでもAndroid開発はできるのか?

初めてのMono for Android開発

WINGSプロジェクト かるあ(監修:山田 祥寛)
2011/08/05
Page1 Page2 Page3 Page4

センサーに触ってみよう

 現在販売中のAndroid端末には、ハードウェア・ベンダによって、加速度センサーやジャイロ・センサー(=角速度を検知するセンサー)、照度センサーといったさまざまなセンサーが搭載されている。

 Mono for Androidでも、Javaで作成したアプリと同様に、AndroidのセンサーをAPIから利用可能だ。ただし、センサーの動作はエミュレータでは確認できない。評価版では実機にアプリを転送できないため、センサーの動作を確認するには、ライセンス版を購入する必要がある点に注意してほしい。

アプリから利用可能なセンサー

 Mono for Androidで利用可能なセンサーの一覧は、Android.Hardware.SensorType列挙体で定義されている。表3にSensorType列挙体で定義されたセンサーの一覧を示す。

列挙体の値 センサーの概要
Accelerometer 加速度センサー
Gyroscope ジャイロ・センサー
Light 照度センサー
MagneticField 地磁気センサー
Orientation 傾きセンサー
Pressure 圧力センサー
Proximity 近傍センサー
Temperature 温度センサー
表3 SensorType列挙体に定義された、アプリから利用できるセンサーの一覧
近傍センサー:物体との距離を検出するセンサー。

 センサー類は、それ単品では使っていても単に数値を取得できるだけだが、アプリやセンサー同士と組み合わせると、さまざまな利用方法が思い浮かぶ。よくある加速度センサーの利用例は、端末の向きに応じた表示の切り替えだが、さらにロケーションや地図アプリと組み合わせれば、ウォーキングの履歴管理などにも利用できる。

 ここでは、照度センサーから値を取得し、端末が置かれた場所の明るさを測定する方法を紹介する。Androidでセンサーを利用する手順は以下のとおりだ。

  1. 端末からセンサーを制御するクラスのインスタンスを取得する
  2. センサーから受信した値を処理するリスナーを定義する
  3. センサーの値を受信するためのリスナーを登録する

 それぞれの手順の内容を詳しく説明していこう。

1. 端末からセンサーを制御するクラスのインスタンスを取得する

 アプリからセンサーを制御するには、現在のアクティビティ・コンテキストのGetSystemServiceメソッドでセンサーを制御するSensorManagerクラスのインスタンスを取得し、そのSensorManagerオブジェクトのGetDefaultSensorメソッドGetSensorListメソッドを利用して制御したセンサーのインスタンスを取得する。

 ただし、基本クラスであるActivityクラスのOnCreateメソッドを呼び出した後でないと、アプリからはセンサーにアクセスできないので注意してほしい。

 リスト4に照度センサーのインスタンスを取得する例を示す。

using Android.App;
using Android.Hardware;
using Android.OS;
using Android.Widget;

public class DeviceStatusActivity : Activity
{
  private SensorManager sensorManager;
  private Sensor lightSensor;

  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);

    // センサーを制御するSensorManagerのインスタンスを取得し
    sensorManager = (SensorManager)GetSystemService(SensorService);
    // 照度センサーのインスタンスを取得する。
    lightSensor = sensorManager.GetDefaultSensor(SensorType.Light);
  }
}
リスト4 センターのインスタンスを取得する例(Activity1.cs)

2. センサーから受信した値を処理するリスナーを定義する

 センサーから値を取得するには、ISensorEventListenerインターフェイスを実装したクラスのOnSensorChangedメソッドを利用する。今回はアクティビティ自身にISensorEventListenerインターフェイスを実装して、センサーから取得した値を画面に表示する。

 ISensorEventListenerインターフェイスは、センサーの値が変更された場合(=OnSensorChangedメソッドの場合)と、センサーを取得する精度が変更された場合(=OnAccuracyChangedメソッドの場合)に、センサーの設定を変更したり、センサーの値を取得したりするためのインターフェイスだ。

 リスト5に照度センサーから値を取得してビューに表示する例を示す。

……省略……

public class DeviceStatusActivity : Activity , ISensorEventListener
{
  ……省略……

  private TextView txtLight;
  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);

    ……省略……

    // ビューの決定とコントロールの取得
    SetContentView(Resource.Layout.DeviceStatus);
    txtLight = FindViewById<TextView>(Resource.Id.txtLight);
  }

  ……省略……

  // センサーの値が変更された際にセンサーから値を取得します。
  public void OnSensorChanged(SensorEvent e)
  {
    if (e.Sensor.Type == SensorType.Light)
      txtLight.Text = e.Values[0].ToString();
  }

  // センサーの精度が変更された際に発生します。
  public void OnAccuracyChanged(Sensor sensor, int accuracy)
  {
  }
}
リスト5 センサーから受信した値を処理するリスナーの定義例(Activity1.cs)

 センサーの値は、SensorEventクラスのValuesプロパティを参照することで取得できる。Valuesプロパティは、センサーから取得された値のリスト(=List<float>型のオブジェクト)として取得できる。加速度センサーなどは、リストの0番目にZ軸の値、1番目にY軸の値、2番目にX軸の値が取得できる。照度センサーでは、センサーからは0番目の値しか利用しないためValuesプロパティの0番目の値をテキストビュー(TextViewコントロール)に表示している。

3. センサーの値を受信するためのリスナーを登録する

 各アプリでは、画面の開始時(=OnResumeメソッド)にSensorManagerオブジェクトのRegisterListenerメソッドで値の取得を行うリスナーを登録し、画面の一時停止時(=OnPauseメソッド)にSensorManagerオブジェクトのUnregisterListenerメソッドでリスナーの登録を解除する(なお、OnResume/OnPauseメソッドは、ISensorEventListenerインターフェイスを実装したクラスのメソッド)。これは、別のアクティビティを表示するなど、アプリがバックグラウンドに回ったときはセンサーからの値の取得をいったん停止させ、再びアプリが表示されたタイミングでセンサーからの値の取得を再開したいためだ。

 リスト6にリスナーの登録と登録解除の例を示す。

……省略……

public class DeviceStatusActivity : Activity , ISensorEventListener
{
  ……省略……

  // 画面の操作を開始する直前に発生するイベントです。
  protected override void OnResume()
  {
    base.OnResume();
    sensorManager.RegisterListener(this, lightSensor, SensorDelay.Ui);
  }
 
  // 画面がバックグラウンドに回る直前に発生するイベントです。
  protected override void OnPause()
  {
    base.OnPause();
    sensorManager.UnregisterListener(this, lightSensor);
  }
}
リスト6 リスナーの登録と登録解除(Activity1.cs)
「lightSensor」は、リスト4で取得した照度センターのインスタンス。

 RegisterListenerメソッドのパラメータは、順に、「リスト5 センサーから受信した値を処理するリスナーの定義例」のコードで定義したリスナーを持つインスタンス(ここでは自らのアクティビティ)と、リスナーを登録するセンサー、センサーから値を取得する精度(タイミング)を設定する。センサーから値を取得する精度(タイミング)は、SensorDelay列挙体に定義されている。表4にSensorDelay列挙体の一覧を示す。

定数 センサーから値を取得する精度
Fastest 0ms
Game 20ms
Ui 60ms
Normal 200ms
表4 SensorDelay列挙体の一覧(単位「ms」:ミリ秒)

 ここでは、それほど高い制度での値の取得は必要ないので、「Ui」(=60ミリ秒)を指定している。

 実行結果を図13に示す。

図13 照度センサーを活用するサンプルの実行結果

 エミュレータで実行した場合は、エミュレータに照度センサーが実装されていないため、値は空のまま変化しない。しかし、実機に配置した場合は、照度によって値が変化する(この例では、明るい場所は「160」、暗い場所は「10」という変化が生じている)。

まとめ

 簡単な例ではあるが、Mono for Androidを利用すると、C#でセンサーの操作を伴うAndroidアプリが作成でき、かつWindows PhoneとAndroidでソース・コードを共有可能だということを理解していただけたかと思う。

 今回見ていただいたように、使い慣れたC#という環境で、複数のプラットフォームに対してコードを共有して利用できるというメリットはとても大きい。ミゲル氏のブログ・エントリによると、7月にボストンで開催予定のMono Spaceで何らの発表があるということなので、Monoの、Xamarinの今後に期待したいと思う。end of article

 

 INDEX
  特集:.NETでもAndroid開発はできるのか?
  初めてのMono for Android開発
    1.Mono for Androidとは/開発環境の構築
    2.書籍検索アプリを作ってみよう(プロジェクト構成の概要)
    3.書籍検索アプリを作ってみよう(画面の作成/Windows Phoneとのコード共有)
  4.センサーに触ってみよう


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間