前回に続き、 reactive4java ネタ。 調子に乗って Android で位置を取得し続けるのを reactive4java を使ってやってみた。
//LocationFunctions.java
/**
* 位置を取得し続ける(finish は呼ばれない)
*/
public static Observable<Location> getCurrentLocationAsObservable(
final Context context, final String provider) {
return Reactive.createWithCloseable(new Func1<Observer<? super Location>, Closeable>() {
private volatile boolean _stop = false;
@Override
public Closeable invoke(final Observer<? super Location> observer) {
final LocationManager locMan = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
final LocationListener listener = new LocationListener() {
@Override
public void onStatusChanged(String provider, int status, Bundle extras) { }
@Override
public void onProviderEnabled(String provider) { }
@Override
public void onProviderDisabled(String provider) {
observer.error(
new InvalidParameterException("LocationProvider disabled."));
}
@Override
public void onLocationChanged(Location location) {
if (_stop) {
return;
}
// 発火
observer.next(location);
}
};
// 位置取得開始
locMan.requestLocationUpdates(provider, 0, 0, listener, Looper.getMainLooper());
return new Closeable() {
@Override
public void close() throws IOException {
if (_stop) {
return;
}
_stop = true;
locMan.removeUpdates(listener);
observer.finish();
}
};
}
});
}
使い方は、方位の時とほとんど同じ。パラメータが Float から Location に代わっただけ。
_stop
フラグは、Listener を unregister しても溜まってるデータは流しちゃうんじゃないか、という事で用意した。
方位のやつは AtomicBoolean を使ったけどこっちは volatile でやってる。確かどっかで 'AtomicBoolean の方が確実に Atomic' って言ってた気がするけど、そもそもそんなに神経質になるところじゃないか。
Observable にすることで、「n秒間位置を取得して貯めて、その中で一番精度の良いものを通す」みたいなことも簡単にできる。
Android の場合、購読開始時に registerXXXListener、Close で unregisterXXXEventListener てのがひとつのパターン。 たぶん BroadcastReceiver にも適用できる。
XXXListener も BroadcastReceiver も Observable でラップしちゃえば、その後は同じように扱えるので便利♪
##追記 9.27 実はこのプログラム、Cold でしたー。というわけで、Hot についての記事を書きました。
##参考