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

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

ただいまの
回答率

90.36%

  • C#

    8214questions

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

  • Android

    6962questions

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

  • Xamarin

    557questions

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

AndroidのStopService()でServiceの別スレッド処理を終了できない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 136

yusuke2721

score 9

Xamarin.Androidで、定期的にGPS情報アップロードを行うアプリを開発しています。

通常はMainActivityのTimer処理でアップロードを行っていますが、
ホームボタン押下等でアプリ終了され、OnStop()に入った場合はServiceを立ち上げて上記処理を行い、
アプリ起動でOnCreate()に入った場合に、Serviceを完全にキルしたいと考えています。

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

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

[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

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("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
            };
        }
    }

}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • amay077

    2019/01/31 17:05

    直接の解決方法ではないですが、「位置情報の取得とアップロード」はもっぱら Service に任せて、MainActivity では Service が開始されていなければ開始する、のではダメなのでしょうか?「アプリ起動中は MainActivity で行い、アプリ終了時のみ Service に行わせる」理由が分からないです。

    キャンセル

  • yusuke2721

    2019/01/31 20:03 編集

    おっしゃる通りでございます…。
    最初にこの方法を知っていれば良かったのですが、設計変更が難しい箇所が多く、このような状況となりました。

    キャンセル

回答 1

check解決した方法

0

Serviceクラスに付けたProcess名で検索して、Killすることでとりあえずうまく動きそうです。
[Service(Name = "com.CompanyName.App.BackgroundService", Exported = true, Process = ":Process")]

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
下記コードを動かすために、上のパーミッションも必要です。

MainActivity.OnCreate()で下記コードを呼び出す

private void KillBgProc()
{
    try
    {
        var amgr = (ActivityManager)this.GetSystemService(Context.ActivityService);
        var list = amgr.RunningAppProcesses;
        if (list != null)
        {
            for (int i = 0; i < list.Count; i++)
            {
                ActivityManager.RunningAppProcessInfo apinfo = list[i];

                var pkgList = apinfo.PkgList;
                if (apinfo.ProcessName.Contains("TestProject.TestProject:Process"))
                {
                    for (int j = 0; j < pkgList.Count; j++)
                    {
                        amgr.KillBackgroundProcesses(pkgList[j]);
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
    }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

同じタグがついた質問を見る

  • C#

    8214questions

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

  • Android

    6962questions

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

  • Xamarin

    557questions

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