RxM4A により Reactive Extensions が使えるようになった ので、以前に Android+reactive4Java でやったコレ を Xamarin.Android でやってみます。

```c# LocationManager.Extenstion.cs
namespace Amay077.Android.Locations
{
static class LocationManagerExtenstion
{
// 渡した Action を OnLocationChanged で実行されるようにしただけ class LocationListener : Java.Lang.Object, ILocationListener { private readonly Action _locationChangedHandler;

        public LocationListener(Action<Location> locationChangedHandler)
        {
            _locationChangedHandler = locationChangedHandler;
        }
        
        #region ILocationListener implementation
        public void OnLocationChanged(Location location)
        {
            _locationChangedHandler(location);
        }
        
        public void OnProviderDisabled(string provider) { }
        public void OnProviderEnabled(string provider) { }
        public void OnStatusChanged(string provider, Availability status, Bundle extras) { }
        #endregion
    }

    public static IConnectableObservable<Location> RequestLocationAsObservable(
        this LocationManager locMan,
        string provider)
    {
        return Observable.Create<Location>(o => 
        {
            try {
                var isStop = false; // RemoveUpdates してもすぐ止まるか分からんので一応フラグ持っとく

                var listener = new LocationListener(l => 
                {
                    if (isStop) return;
                    o.OnNext(l);
                });

                // 位置取得開始
                locMan.RequestLocationUpdates(provider, 0, 0, listener);
                
                return () => // Dispose() した時に停止
                {
                    if (isStop) return;
                    isStop = true;
                    locMan.RemoveUpdates(listener);
                    o.OnCompleted();
                };

            } catch (Exception ex) {
                o.OnError(ex);
                return () => { /* empty */ };
            }
        }).Publish(); // Hot な Observable に
    }
} } ```

LocationManager の拡張メソッドにしたいので、クラス名を慣例に習って LocationManager.Extenstion.cs に、メソッド RequestLocationAsObservable の第一引数に this を付けてます。

LocationListener Inner クラスは、C# では匿名クラスが使えないので、コンストラクタで指定した ActionOnLocationChanged で呼ばれるようにしただけです。

RequestLocationAsObservable メソッドがメイン。やってることは reactive4Java と同じです。Hot な Observable にしたので、最後に .Publish() してるので、返値が IConnectableObservable になってます。

さて使う方。

```c# Howtouse.cs
using Amay077.Android.Locations; // 拡張メソッドを使えるように

<省略> // LocationManager を得る var locationMan = (LocationManager)context.GetSystemService(Context.LocationService); // RequestLocationAsObservable があたかも LocationManager のメンバのよ(ry var observable = locationMan.RequestLocationAsObservable(LocationManager.GpsProvider); observable.Take(3) // 3回取得 .Timeout(new TimeSpan(10000)) // 10秒待って取得できなかったらタイムアウト .Subscribe( l => { Android.Util.Log.Debug(TAG, String.Format("received: {0}/{1}", l.Latitude, l.Longitude)); }, // 位置が取得される度に呼ばれる e => Android.Util.Log.Debug(TAG, "error:" + e.Message), // エラー(タイムアウト含む)の時呼ばれる () => Android.Util.Log.Debug(TAG, "finished.")); // 全部終わったら呼ばれる observable.Connect(); // 接続開始 ``` Reactive Extensions と C# の拡張メソッドなどのおかげで、Java よりもずいぶんとすっきり書けました。
Xamarin
Android
C#
ReactiveExtensions

published

Ads

Read more!

amay077

Microsoft MVP(Xamarin). フルリモートワーカー. Geospatial Mobile app developer. Love C#.

amay077 amay077