質問編集履歴

1 不要コード削除

yusuke2721

yusuke2721 score 13

2019/01/31 18:12  投稿

AndroidのStopService()でServiceの別スレッド処理を終了できない
Xamarin.Androidで、定期的にGPS情報アップロードを行うアプリを開発しています。
通常はMainActivityのTimer処理でアップロードを行っていますが、
ホームボタン押下等でアプリ終了され、OnStop()に入った場合はServiceを立ち上げて上記処理を行い、
アプリ起動でOnCreate()に入った場合に、Serviceを完全にキルしたいと考えています。
```C#
var context = this.ApplicationContext;
context.StopService(new Intent(context, typeof(BackgroundService)));
```
上記のコードをOnCreate()やTimer処理内で実行すると、
開発者向けオプション内の「実行中のアプリ」リストからはクリアされているのですが、
「実行中のアプリ→キャッシュしたプロセスを表示」リストには残存しており、おそらくそれが原因で、Serviceがリスタートしているようです。
いわゆるゾンビ状態となり、Serviceを終了できず困っています。
「キャッシュしたプロセスを表示」リストから、バックグラウンドプロセスを終了させる方法はございますでしょうか。
よろしくお願いいたします。
~開発環境等~
Visual Studio 2017
Xamarin.Android
Android 7.1 (APIレベル25 - Nougat)
MainActivity.cs
```C#
public class MainActivity : Activity
{   
   protected override void OnCreate(Bundle bundle)
   {
       base.OnCreate(bundle);
       SetContentView(Resource.Layout.Main);
       //サービスがあれば終了させる
       var context = this.ApplicationContext;
       context.StopService(new Intent(context, typeof(BackgroundService)));
   }
   
   protected async override void OnStop()
   {
       //サービスを起動
       var context = this.ApplicationContext;
       var serviceIntent = new Intent(context, typeof(BackgroundService));
       serviceIntent.AddFlags(ActivityFlags.NewTask);
       context.StartService(serviceIntent);
       base.OnStop();
       System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
   }
}
```
BackgroundService.cs
```C#
[Service(Name = "com.CompanyName.App.BackgroundService", Exported = true, Process = ":Process")]
public class BackgroundService : Service
{
   /// <summary>
   ///
   /// </summary>
   Thread thread;
   /// <summary>
   ///
   /// </summary>
   /// <param name="intent"></param>
   /// <returns></returns>
   public override IBinder OnBind(Intent intent)
   {
       return null;
   }
   /// <summary>
   ///
   /// </summary>
   /// <param name="intent"></param>
   /// <param name="flags"></param>
   /// <param name="startId"></param>
   /// <returns></returns>
   [return: GeneratedEnum]
   public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
   {
       try
       {
           thread = new Thread(() =>
           {
               //var bundle = new Bundle();
               //global::Xamarin.Forms.Forms.Init(this, bundle);
               // 別スレッドでWhile処理を用いてアップロードを実行
               BackgroundThread.Main();
           });
           thread.Start();
           return StartCommandResult.NotSticky;
       }
       catch(Exception ex)
       {
           return StartCommandResult.NotSticky;
       }
   }
   /// <summary>
   ///
   /// </summary>
   public override void OnDestroy()
   {
       try
       {
           base.OnDestroy();
           thread.Interrupt();
           thread = null;
           StopSelf();
       }
       catch (Exception ex)
       {
       }
   }
}
```
BackgroundThread.cs
```C#
public static class BackgroundThread
{
   /// <summary>
   /// GPS
   /// </summary>
   private static IGeolocator _GeoLocator;
   /// <summary>
   /// GPS取得データ
   /// </summary>
   private static Position _LastPos;
   public static async void Main()
   {
       var mac = AppUtil.GetDeviceMacAddress();
       _GeoLocator = CrossGeolocator.Current;
       _GeoLocator.DesiredAccuracy = 10;
       _GeoLocator.AllowsBackgroundUpdates = true;
       _GeoLocator.PositionChanged -= Geolocator_PositionChanged;
       _GeoLocator.PositionChanged += Geolocator_PositionChanged;
       await _GeoLocator.StartListeningAsync(1000, 0, true);
       while (true)
       {
           try
           {
               // 位置情報をサーバーへPOST
               using (var httpClient = new HttpClient())
               {
                   httpClient.Timeout = TimeSpan.FromMilliseconds(10000);
                   httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                   // JSON形式に
                   var jArray = new JArray();
                   var jObj = new JObject();
                   jObj.Add("DeviceMacAddress", mac);
                   //jObj.Add("GpsDeviceInfoCode", -999);  
                   //jObj.Add("DeviceInfoCodeDatetime", DateTime.Now);  
                   jObj.Add("GpsAccelerometerX", 0);
                   jObj.Add("GpsAccelerometerY", 0);
                   jObj.Add("GpsAccelerometerZ", 0);
                   jObj.Add("SuddenBrakeFlg", false);  
                   jObj.Add("SuddenAccelFlg", false);  
                   jObj.Add("SuddenTurnFlg", false);  
                   jObj.Add("GpsDatetime", _LastPos.Timestamp);
                   jObj.Add("GpsLat", _LastPos.Latitude);
                   jObj.Add("GpsLon", _LastPos.Longitude);
                   jObj.Add("GpsSpeed", _LastPos.Speed);
                   jObj.Add("GpsDirection", _LastPos.Heading);
                   jObj.Add("GpsAccuracy", _LastPos.Accuracy);
                   jArray.Add(jObj);
                   var content = new StringContent(jArray.ToString(), System.Text.Encoding.UTF8, "application/json");
                   //httpClient.PostAsync(GetString(Resource.String.DomainUrl) + GetString(Resource.String.ApiValues), content);
                   await httpClient.PostAsync(@"http://www.xxx.com/api/values/", content);
               }
           }
           catch (Exception ex)
           {
               string message = ex.Message;
               Console.WriteLine(ex.Message);
           }
           Thread.Sleep(10000);
       }
   }
   /// <summary>
   /// 位置情報更新
   /// </summary>
   /// <param name="sender"></param>
   /// <param name="e"></param>
   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,
               Speed = e.Position.Speed,
               Heading = e.Position.Heading,
               Accuracy = e.Position.Accuracy
           };
       }
   }
}
```
  • C#

    10493 questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Android

    8018 questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Xamarin

    694 questions

    Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る