Androidでは様々なセンサーに対応しています。
センサーとはさまざまな物理量(温度や角度など)を検知・計測する装置のことです。
スマートフォンにはさまざまなセンサーが内蔵されており、スマートフォンが現在おかれている環境の情報を数値として得ることができます。
たとえば、スマートフォン同士をシェイクすることでアドレス帳を交換するアプリはスマートフォンがシェイクされたことをセンサーが検知することによって実現しています。
Android 4.0で対応しているセンサーには、加速度センサーの他にも以下のようなものがあります。
[table “172” not found /]これらのセンサーを利用するには以下のような設定が必要です。
今回はAndroidでセンサーを利用する方法について解説します。
詳しくは続きからご覧ください。
SensorManagerとは?
Androidでセンサーを使おうとしたときに、まずはじめにしなければいけないことはSensorManagerを取得することです。
先述のようにセンサーにはさまざまな種類が存在するため、センサーの種類が変わればその制御方法も当然ながら変わります。しかし、プログラマがいちいちセンサーの詳細な制御方法を意識しなければセンサーを利用できないのではとても不便ですよね。
SensorManagerはこのようなセンサーによって異なる制御方法の違いを吸収してくれるクラスです。
これによりプログラマはセンサーの種類に関わらず、使いたいセンサーを指定するだけでセンサーの値を取得することができるようになります。
SensorManagerを取得する
それではまずはじめにそのSensorManagerを取得しましょう。
SensorManagerを取得するにはContextクラスに定義されているgetSystemServiceメソッドを使います。
getSystemServiceメソッドはSensorManagerのようなマネージャーを取得するメソッドです。
(ほかにもGPSから位置情報を取得する場合に利用するLocationManagerなどがあります。)
引数に取得したいマネージャーを指定して実行します。SensorManagerを使う場合はContext.SENSOR_SERVICEを指定します。
■src/SensorActivity.java
// SensorManagerのインスタンスを取得する mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
イベントリスナーを実装する
次にイベントリスナーを登録します。
イベントリスナーとは「何らかのイベントが発生したときに呼ばれるメソッドを持つクラス」のことです。
たとえば、マウスのイベントの場合だと「クリックされた」、「ドラッグされた」といったことがイベントになりますが、これらのイベントに反応して呼ばれるメソッドがプログラム上に必要になります。
Androidでは、イベントの種類ごとにイベントを処理するために必要なメソッドがインタフェースとして定義されています。センサーイベントにはhardwareクラスにSensorEventListenerインタフェースが用意されているので、これをActivityに実装して具体的な処理を実装していく流れになります。
SensorEventListenerインタフェースには2つのメソッドが定義されています。
- onAccuracyChanged : センサーの精度が変更されると呼ばれる
- onSensorChanged : センサーの値が変化すると呼ばれる
実際にSensorEventListenerインタフェースを実装すると以下のようになります。
■src/SensorActivity.java
public class SensorActivity extends Activity implements SensorEventListener { (...略...) @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // センサーの精度が変更されると呼ばれる } @Override public void onSensorChanged(SensorEvent event) { // センサーの値が変化すると呼ばれる } }
センサーの値を使って何かしたい場合にはonSensorChangedメソッドを使います。
onSensorChangedメソッドの引数にあるSensorEventには下表のように、値に変化があったセンサーの種類や、タイムスタンプ、検出した値、精度が格納されます。
検出値が格納されるvalues配列はセンサーの種類ごとに配列の内容の意味が変わります。
たとえば照度センサ、地磁気センサ、加速度センサの配列の内容を比較すると以下のようになります。
この情報はAndroid Developersに公開されているので、使用するセンサーごとに確認する必要があります。
2つ以上センサーを使いたい場合
アプリで使うセンサーが1つの場合は特に問題はありませんが、2つ以上のセンサーを扱う場合はセンサーの種類ごとに処理する必要があります。onSensorChangedメソッドは監視対象に設定したセンサーのいずれかに変化が合った場合に反応するからです。
event.sensor.getTypeメソッドを利用すると、イベントが発生したセンサーの種類を取得することができます。
以下のようにして、イベントが発生したセンサーをチェックするようにしましょう。
■src/SensorActivity.java
@Override public void onSensorChanged(SensorEvent event) { // 値が変化したセンサーが照度センサーだった場合 if (event.sensor.getType() == Sensor.TYPE_LIGHT) { // 処理 } // 値が変化したセンサーが近接センサーだった場合 else if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { // 処理 } }
イベントリスナーの登録と登録解除
では、リスナーをAndroidのシステムに登録してセンサーを監視対象にします。
システムに登録しておかないと、センサーが実際に値を検出してもAndroidがイベントとしてアプリケーションに通知してくれません。
リスナーの登録にはSensorManagerクラスのregisterListenerメソッドを使います。
registerListenerメソッドの引数にはセンサーイベントを取得するリスナー、取得するセンサーの種類、取得する頻度を設定します。
registerListener(SensorEventListener listener, Sensor sensor, int rate)
[table “182” not found /]取得頻度を表すrateには以下の定数を指定することができます。
高頻度に設定するほどバッテリーの消耗は激しくなるので、無闇に高頻度設定するのは良くないでしょう。
具体的なregisterListenerの使い方は以下のようになります。
■src/SensorActivity.java
// センサーのオブジェクトリストを取得する List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_LIGHT); // イベントリスナーを登録する if (sensors.size() > 0) { Sensor s = sensors.get(0); mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_UI); }
2行目のgetSensorListメソッドは指定したセンサーのオブジェクトをリストで取得します。
指定したセンサーが存在しない場合はリストのサイズが0になるので、5行目のようにリストのサイズをチェックすることでセンサーが利用可能か確認しています。
そして、6行目でリストからセンサーのオブジェクトを取得して、7行目のregisterListenerメソッドでリスナーを登録しています。
逆にイベントリスナーの登録解除はSensorManagerクラスのunregisterListenerメソッドを使います。
アプリがバックグラウンドに遷移する場合、ずっとセンサーが動き続けてしまうとバッテリーの無駄になってしまうので、unregisterListenerメソッドで登録を解除しておきましょう。
■src/SensorActivity.java
// イベントリスナーの登録を解除 protected void onPause() { super.onPause(); if (mSensorManager != null) { mSensorManager.unregisterListener(this); } }
サンプルアプリ
それでは最後に、周囲の明るさを検出する照度センサを使ったサンプルアプリを使っておさらいをします。取得した明るさに応じてキャラクターのセリフと画像の透明度を変更します。
■src/SensorActivity.java
public class SensorActivity extends Activity implements SensorEventListener { private SensorManager mSensorManager; private TextView mTextView; private ImageView mImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // SensorManagerのインスタンスを取得する mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); // ImageViewのインスタンスを取得して、画像を設定する mImageView = (ImageView) findViewById(R.id.image); mImageView.setImageResource(R.drawable.tb); // TextViewのインスタンスを取得する mTextView = (TextView) findViewById(R.id.value); } @Override protected void onResume() { super.onResume(); // 照度センサーを指定してオブジェクトリストを取得する List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_LIGHT); // 照度センサーがサポートされているか確認してから登録する if (sensors.size() > 0) { Sensor s = sensors.get(0); mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_UI); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // onAccuracyChangedは今回は未使用 } @Override public void onSensorChanged(SensorEvent event) { switch(event.sensor.getType()){ case Sensor.TYPE_LIGHT: // 現在の明るさを取得 int light_value = (int)(event.values[0]); // 明るさが200未満のときのセリフ if (light_value < 200) { mTextView.setText("暗いから眠くなってきたにゃ。"); // 明るさが200以上のときのセリフ } else { mTextView.setText("明るすぎて眼が痛いにゃ。"); } // 明るさから透明度を求める int alpha = light_value; if (alpha > 255) // 透明度の上限値を255に設定する alpha = 255; // ImageViewに透明度を設定する mImageView.setAlpha(alpha); break; } } }
まず、1行目でSensorEventListenerインタフェースをActivityに実装しています。
SensorEventListenerインタフェースを実装されると、onAccuracyChangedメソッド(38行目)とonSensorChangedメソッド(43行目)が自動挿入されます。
onSensorChangedメソッド内では照度センサのイベントを処理します。
44行目のevent.sensor.getTypeメソッドで照度センサのイベントであることを確認し、
47行目で照度センサが取得した値をevent.values[0]からlight_value変数に代入しています。
その後、50行目-56行目で明るさに応じてセリフを設定しています。
また、59行目-64行目では明るさによって画像の透明度を設定しています。
24行目のonResumeメソッド内で照度センサーのイベントリスナを登録しています。
28行目で照度センサーを指定し、オブジェクトを取得します。
そして31-33行目で照度センサーがサポートされていることを確認し、イベントリスナーを登録します。
まとめ
長くなりましたが、以上がAndroidでセンサーを扱う手順になります。
どのセンサーを使う場合もSensorManagerを取得して、任意の処理を実装したイベントリスナーをシステムに登録する。そしてSensorEventを介して発生したイベントの情報を取得するという手順は基本的に変わりません。
ただし、使うセンサーによって取得した値の扱い方が異なる点だけ押さえておきましょう。
以上、お疲れさまでした。