今回は、アプリを更新するもう一つの方法、「シェイクで更新」について説明します。ご存知のように、ドロップダウン方式を採用しているアプリは多く、画面上で指をスライドさせさえすれば、インターフェイスを更新することができます。
ドロップダウンによる更新も便利ですが、スマートフォンのセンサーを利用したシェイクリフレッシュという方法もあります。この方法では、指をスワイプする必要はなく、スマートフォンを振るだけでインターフェイスが更新されます:
実装方法
シェイクリフレッシュ機能を実現するには、重力加速器を使用する必要があります。
まず、携帯電話を振ってリフレッシュしたり、移動させたりする際に誤操作が発生しないようにする必要がありますが、ここでは、ユーザが希望する振る操作を確実に捉えるためのセンサーの制御を実装する必要があります。また、このロジック操作の実装では、UIコードと分離する必要があり、インターフェイスロジックのコードを他のコードと混在させないことが推奨され、独立して再利用することが容易です。まず、ShakeEventManager クラスを作成します:
public class ShakeEventManager implements SensorEventListener {
..
}
センサーをリッスンするためには、ここでSensorEventListenerインターフェイスを実装し、重力加速度センサーを操作して、書いたクラスをイベントリスナーとして登録する必要があります:
public void init(Context ctx) {
sManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
s = sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
register();
}
次に register() メソッドを実装します:
public void register() {
sManager.registerListener(this, s, SensorManager.SENSOR_DELAY_NORMAL);
}
refreshイベントがトリガーされると、ユーザーが意図的に携帯電話を振っていることを確認するために、いくつかの条件をテストする必要があります:
- 加速度はある臨界値より大きくなければなりません;
- 一部の固定加速度センサーイベントはオフに設定する必要があります;
- これらのイベントは、一定の期間内に発生する必要があります。
この実装ロジックのコードは、onSensorChanged メソッドに記述されており、アクセラレータの値が有効になるたびに呼び出されます。***ステップ この加速度の値を計算します。ここで、3つの座標の加速度値を知り、3つの方向の重力の値を差し引く必要があります。Androidの公式チュートリアルのドキュメントで説明されているように、最初に重力の成分を差し引くフィルタリングのレイヤーがあり、それから他の座標成分が処理されます:
private float calcMaxAcceleration(SensorEvent event) {
gravity[0] = calcGravityForce(event.values[0], 0);
gravity[1] = calcGravityForce(event.values[1], 1);
gravity[2] = calcGravityForce(event.values[2], 2);
float accX = event.values[0] - gravity[0];
float accY = event.values[1] - gravity[1];
float accZ = event.values[2] - gravity[2];
float max1 = Math.max(accX, accY);
return Math.max(max1, accZ);
}
calcGravityForceメソッドを見てみましょう:
// Low pass filter
private float calcGravityForce(float currentVal, int index) {
return ALPHA * gravity[index] + (1 - ALPHA) * currentVal;
}
ここでは****の加速度値を知った上で判定ロジックを実装しています:
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
float maxAcc = calcMaxAcceleration(sensorEvent);
Log.d("SwA", "Max Acc ["+maxAcc+"]");
if (maxAcc >= MOV_THRESHOLD) {
if (counter == 0) {
counter++;
firstMovTime = System.currentTimeMillis();
Log.d("SwA", "First mov..");
} else {
long now = System.currentTimeMillis();
if ((now - firstMovTime) = MOV_COUNTS)
if (listener != null)
listener.onShake();
}
}
}
コードを見ると、3行目で加速度の値を計算し、それをしきい値と比較しています。もしそれが***番目の揺れであれば、現在時刻を保存し、一定時間内に他のイベントがトリガーされたかどうかを調べます。すべての条件が満たされると、インターフェースのコールバックメソッドが呼び出されます:
public static interface ShakeListener {
public void onShake();
}
テストアプリ
シェイク・イベント管理は上記で実装しましたので、これを使うには新しいシンプルなAppを作成する必要があります。ListViewを持つ単純なActivityを作成し、ListViewが振られたときにListViewを更新させるだけです:
public class MainActivity extends ActionBarActivity implements ShakeEventManager.ShakeListener {
....
@Override
public void onShake() {
// We update the ListView
}
}
ご覧のように、ユーザーが携帯電話を振るとメソッドが呼び出されるため、インターフェイスは5行目でリフレッシュされます。
*** このリスナーは、アプリが停止したときに登録を解除する必要があります。また、アプリが起動し直したら、リスナーを再登録する必要があります:
Override
protected void onResume() {
super.onResume();
sd.register();
}
@Override
protected void onPause() {
super.onPause();
sd.deregister();
}
要約すると、シェイクリフレッシュ機能が実装されました。