質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

staticクラスでSensorManagerを使用する方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 397

yusuke2721

score 13

Xamarin.Androidで、端末データ(GPS, 加速度等)のアップロードを定期的に行うアプリを開発しています。

Activityで実装していたアップロード処理を、Serviceを用いて別スレッドにて行うよう実装変更したいのですが、
public class MainActivity : Activity, ISensorEventListener と記述してSensorManagerを使用していた部分を、
どのように書き換えればよいのか分からず、行き詰まっております。

staticやinterfaceを十分に理解できておらずお手上げ状態なのですが、
何かヒントがございましたらご教示いただけませんでしょうか。
よろしくお願いいたします。

~開発環境等~
Visual Studio 2017
Xamarin.Android
Android 7.1 (APIレベル25 - Nougat) 

Service内、別スレッドにてBackgroundThread.Main()を起動

[Service(Name = "com.CompanyName.App.BackgroundService", Exported = true, Process = ":Process")]
public class BackgroundService : Service
{
    Task task;

    public override IBinder OnBind(Intent intent)
    {
        return null;
    }

    [return: GeneratedEnum]
    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    {
        task = new Task(() => BackgroundThread.Main());
        task.Start();
        return StartCommandResult.NotSticky;
    }

    public override void OnDestroy()
    {
        base.OnDestroy();
        task.Dispose();
        task = null;
        StopSelf();
    }
}

別スレッドで行うセンサー処理やアップロード処理(Timerでループ)

//public static class BackgroundThread : ISensorEventListener 
//↑「静的クラスではインターフェイスを実装できません」とのこと
public static class BackgroundThread
{
    private static Context _Context;
    private static IGeolocator _GeoLocator;
    private static Position _LastPos;
    private static System.Timers.Timer _SecTimer;
    private static SensorManager _SensorManager;
    private static string _MacAddress;
    private static double[] _Accel = new double[] { 0, 0, 0 };

    public static async void Main()
    {
        _Context = MainApplication.GetContext();
        _MacAddress = AppUtil.GetDeviceMacAddress();

        _GeoLocator = CrossGeolocator.Current;
        _GeoLocator.DesiredAccuracy = 10;
        _GeoLocator.AllowsBackgroundUpdates = true;
        _GeoLocator.PositionChanged += Geolocator_PositionChanged;
        await _GeoLocator.StartListeningAsync(1000, 0, true);

        // 加速度センサー
        //_SensorManager = (SensorManager)GetSystemService(Context.SensorService);
        //_SensorManager.RegisterListener(this, _SensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Normal);

        _SecTimer = new System.Timers.Timer();
        _SecTimer.Elapsed += (sender, args) => SecTimer_Tick();
        _SecTimer.Interval = 10 * 1000;
        _SecTimer.Start();
    }

    //public void OnSensorChanged(SensorEvent e)
    //{
    //    switch (e.Sensor.Type)
    //    {
    //        case SensorType.Accelerometer:
    //            _Accel[0] = acc.X;
    //            _Accel[1] = acc.Y;
    //            _Accel[2] = acc.Z;
    //            break;
    //        default:
    //            break;
    //    }
    //}
    //
    //public void OnAccuracyChanged(Sensor sensor, [GeneratedEnum] SensorStatus accuracy)
    //{
    //
    //}

    private static void Geolocator_PositionChanged(object sender, PositionEventArgs e)
    {
        if (e.Position.Accuracy <= 100)
        {
            _LastPos = new Position
            {
                Timestamp = e.Position.Timestamp.ToLocalTime(),
                Latitude = e.Position.Latitude,
                Longitude = AppUtil.ToRoundDown(e.Position.Longitude,
            };
        }
    }

    private static async void SecTimer_Tick()
    {
        try
        {
            // 情報をサーバーへPOST
            using (var httpClient = new HttpClient())
            {
                httpClient.Timeout = TimeSpan.FromMilliseconds(10000);
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                var jArray = new JArray();
                var jObj = new JObject();
                jObj.Add("DeviceMacAddress", _MacAddress);
                jObj.Add("AccelerometerX", _Accel[0]);
                jObj.Add("AccelerometerY", _Accel[1]);
                jObj.Add("AccelerometerZ", _Accel[2]);
                jObj.Add("GpsDatetime", _LastPos.Timestamp);
                jObj.Add("GpsLat", _LastPos.Latitude);
                jObj.Add("GpsLon", _LastPos.Longitude);
                jArray.Add(jObj);

                var content = new StringContent(jArray.ToString(), System.Text.Encoding.UTF8, "application/json");
                await httpClient.PostAsync(_Context.GetString(Resource.String.DomainUrl) + _Context.GetString(Resource.String.ApiValues), content);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

staticクラスはインターフェースを実装できないので、staticクラスを使わずにシングルトンにするには以下のようにします。

public class BackgroundThread : ISensorEventListener 
{
    public static BackgroundThread Instance { get; } = new BackgroundThread();

    private Context _Context;
    private IGeolocator _GeoLocator;
    private Position _LastPos;
    private System.Timers.Timer _SecTimer;
    private SensorManager _SensorManager;
    private string _MacAddress;
    private double[] _Accel = new double[] { 0, 0, 0 };

    private BackgroundThread()
    {
    }

    public async void Main()
    {
        _Context = MainApplication.GetContext();
        _MacAddress = AppUtil.GetDeviceMacAddress();

        _GeoLocator = CrossGeolocator.Current;
        _GeoLocator.DesiredAccuracy = 10;
        _GeoLocator.AllowsBackgroundUpdates = true;
        _GeoLocator.PositionChanged += Geolocator_PositionChanged;
        await _GeoLocator.StartListeningAsync(1000, 0, true);

        // 加速度センサー
        _SensorManager = (SensorManager)GetSystemService(Context.SensorService);
        _SensorManager.RegisterListener(this, _SensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Normal);

        _SecTimer = new System.Timers.Timer();
        _SecTimer.Elapsed += (sender, args) => SecTimer_Tick();
        _SecTimer.Interval = 10 * 1000;
        _SecTimer.Start();
    }

    public void OnSensorChanged(SensorEvent e)
    {
        ...
    }

    public void OnAccuracyChanged(Sensor sensor, [GeneratedEnum] SensorStatus accuracy)
    {

    }

    private void Geolocator_PositionChanged(object sender, PositionEventArgs e)
    {
        ...
    }

    private async void SecTimer_Tick()
    {
        ...
    }
}

呼び出すときは、こうします。

task = new Task(() => BackgroundThread.Instance.Main());

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/05 15:46

    実行することができました!
    Singletonパターンを知らなかったので、勉強になりました。
    ありがとうございます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる