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

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

ただいまの
回答率

90.83%

  • Android

    6118questions

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

【Android】Serviceの停止方法について

受付中

回答 0

投稿

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

前提・実現したいこと

Androidアプリを開発しています。作成中のプログラムは「スタートボタンをクリックすると、バックグラウンドにて、一定時間後待機したのち処理を開始する」というものです。
現在は、バックグラウンド処理を途中で停止させる機能を追加実装するところでハマってしまいました。そこでServiceを停止させる方法についてアドバイス頂きたいです。
ソースコード内のコメントの仕方など、初心者で我流のためお見苦しいところがあるかも知れませんが、どうかよろしくお願いいたします。

発生している問題・エラーメッセージ

疑問1:こちらのServiceはそもそも停止しているのか(ストップボタンを押す押さないで挙動が異なるも、本当に停止しているようには思えない)。
疑問2:停止していない場合に、次にTryするべきことについてアドバイス。

コードを実行して得られるLogはこちらです。

◆ストップボタンを押さない場合
12-18 13:55:33.353 16600-16600/com.example.android.asobisugi D/Check: Inside findLauncherApp: com.sonyericsson.home
12-18 13:55:48.224 16600-16600/com.example.android.asobisugi D/Check: I'm inside onCreate() in CountTimeService.class.
12-18 13:55:48.238 16600-16600/com.example.android.asobisugi D/Check: [service starting] I'm inside onStartCommand().
12-18 13:55:48.245 16600-19103/com.example.android.asobisugi D/Check: 1分待機. Thread ID: 13221
12-18 13:56:48.280 16600-19103/com.example.android.asobisugi D/Check: After Thread.sleep() and stopSelf() Thread ID: 13221
12-18 13:56:48.281 16600-16600/com.example.android.asobisugi D/Check: onDestroy()が呼出。Thread ID: 1

◆ストップボタンを押した場合
12-18 13:59:18.976 16600-16600/com.example.android.asobisugi D/Check: I'm inside onCreate() in CountTimeService.class.←スタートボタン押下
12-18 13:59:18.978 16600-16600/com.example.android.asobisugi D/Check: [service starting] I'm inside onStartCommand().
12-18 13:59:18.982 16600-19369/com.example.android.asobisugi D/Check: 1分待機. Thread ID: 13224
12-18 14:00:19.020 16600-16600/com.example.android.asobisugi D/Check: onDestroy()が呼出。Thread ID: 1←ストップボタン押下
12-18 14:00:19.020 16600-19369/com.example.android.asobisugi D/Check: After Thread.sleep() and stopSelf() Thread ID: 13224

該当のソースコード

※Serviceの停止処理はMainActivityから行うようにしています。(下部参照)

public class CountTimeService extends Service {

private final String TAG = "Check";

// onCreate()にて初期化
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;

String action;
String launcherPackName;

// Looperから受け取る処理を実行するHandlerを継承したクラス
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
try {
Log.d(TAG, "1分待機. Thread ID: " + Thread.currentThread().getId());
Thread.sleep(60000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}

stopSelf(msg.arg1);
Log.d(TAG, "After Thread.sleep() and stopSelf() Thread ID: " + Thread.currentThread().getId());
}
}

@Override
public void onCreate() {
Log.d(TAG, "I'm inside onCreate() in CountTimeService.class.");
// 別スレッドを生成
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();

// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "[service starting] I'm inside onStartCommand().");
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

action = intent.getAction();
launcherPackName = intent.getPackage();

Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);

return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}

@Override
public void onDestroy() {
Log.d(TAG, "onDestroy()が呼出。Thread ID: " + Thread.currentThread().getId());
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}

※MainActivityのonCreate()にて以下のclickListenerから停止のIntentを投げる仕組み。

Button stopBtn = (Button) findViewById(R.id.stop_btn);
stopBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(
MainActivity.this, CountTimeService.class);
stopService(intent);
Log.d("Check", "stopService()を実行。 Thread ID: " + Thread.currentThread().getId());
}
});

試したこと

【経過】
①IntentServiceを使ってバックグラウンド処理を実装。
→順次処理のため?、停止対象のIntentServiceが完了するまで停止処理が実行されない。
→booleanの変数を追加し、プログラムの要所要所にIf文でstopSelf()/stopService()を呼び出すようにした(https://stackoverflow.com/questions/11258083/how-to-force-an-intentservice-to-stop-immediately-with-a-cancel-button-from-an-a)。スレッドが違うからか?うまくいかない。
②AsyncTaskを使うことも考えたが、長時間処理には非推奨のため断念(使い方によっては30分~数時間動作する想定)。
③ノーマルなServiceを使ってみた(※現在)

補足情報(言語/FW/ツール等のバージョンなど)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

まだ回答がついていません

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

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

関連した質問

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

  • Android

    6118questions

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