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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

1回答

15308閲覧

スレッド処理のRunnableを終了させる-handller#removeCallbacksが機能しない

mercurian-teto

総合スコア75

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

1クリップ

投稿2018/04/28 17:57

編集2018/04/28 17:59

handler#removeCallbacksを呼び出してrunnableを終了させようとしたのですが
終了されません。実機で試してみたのですが、何度やってもホーム画面に戻っても
スレッド処理が終了した後に処理されるToastの

Toast.makeText(MainActivity.this, "遅延ボタンが押されました", Toast.LENGTH_LONG).show();

が実行されてしまいます。
handler.removeCallbacks(runnable);
HandlerやRunnableのインスタンスも宣言しているはずなのに
なぜスレッドが終了されないのでしょうか。

package com.distractionapp.restrict.tienn; import android.app.Activity; import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { /** プログレスバー */ private ProgressDialog mPrgDlg; public final int minutes =600; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 実行中ダイアログの生成・初期化 mPrgDlg = new ProgressDialog(this); mPrgDlg.setTitle("スレッド実行中"); mPrgDlg.setMessage("しばらくお待ちください。"); mPrgDlg.setIndeterminate(false); mPrgDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER); mPrgDlg.setMax(100); // 最大値 mPrgDlg.incrementProgressBy(0); // 初期値 // ボタンクリック処理 Button btnStart = (Button)findViewById(R.id.btn); btnStart.setOnClickListener(new OnClickListener() { public void onClick(View v) { // ダイアログ表示 mPrgDlg.show(); // スレッド生成・実行 Thread thread = new Thread(runnable); thread.start(); } }); } /** * スレッド処理 */ Runnable runnable = new Runnable() { @Override public void run() { for (int i=0; i<100; i++) { try { Thread.sleep(100); mPrgDlg.setProgress(i+1); } catch (InterruptedException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } Message msg = new Message(); msg.arg1 = 0; handler.sendMessage(msg); } }; /** * スレッドの終了を受信するハンドラ */ private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // 実行中ダイアログを閉じる mPrgDlg.dismiss(); Toast.makeText(MainActivity.this, "遅延ボタンが押されました", Toast.LENGTH_LONG).show(); }; }; @Override public void onPause(){ super.onPause(); //finishAndRemoveTask(); handler.removeCallbacks(runnable); } }

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

keicha_hrs

2018/04/29 06:25 編集

目的としては「アプリを一度閉じて再度開いてボタンを押したとき」にはhandleMessage()にある内容を実行しないようにしたい、ということですよね?それが出来たとして、そうするとProgressDialogも閉じられないことになるので、これがずっと出っぱなしになるのが目標ということですか?
mercurian-teto

2018/04/29 07:53

Onpaseでプログレスダイアログと進行しているスレッドの処理を中断して、スレッド進行後の処理もできないようにしたいです。アプリはAndroid6.0で使えるようにしたいです。
guest

回答1

0

ベストアンサー

Handler#removeCallbacks()が有効になるのは、このHandlerに結びついているRunnableです。参考にしたページでは、Handler#postDelayed()の引数に与えたRunnableをremoveCallbacks()で削除しようとしています。それに対し、今回の質問のコードにあるRunnableはThreadに結びついているもので、Handlerとは何の関係も持っていません。ですからここでのremoveCallbacks()は何も機能しません。

今回の目的を果たすには、動作中のThreadをいかに中断させるかという方向で考えた方がいいでしょう。改修してみたコードを下記に記します(今回は先に動作検証しました(^^;)。

Java

1public class MainActivity extends AppCompatActivity { 2 /** 3 * プログレスバー 4 */ 5 private ProgressDialog mPrgDlg; 6 public final int minutes = 600; 7 private Thread mThread; 8 9 @Override 10 public void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.activity_main); 13 14 // 実行中ダイアログの生成・初期化 15 mPrgDlg = new ProgressDialog(this); 16 mPrgDlg.setTitle("スレッド実行中"); 17 mPrgDlg.setMessage("しばらくお待ちください。"); 18 mPrgDlg.setIndeterminate(false); 19 mPrgDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER); 20 mPrgDlg.setMax(100); // 最大値 21 mPrgDlg.incrementProgressBy(0); // 初期値 22 23 // ボタンクリック処理 24 Button btnStart = (Button) findViewById(R.id.btn); 25 btnStart.setOnClickListener(new View.OnClickListener() { 26 public void onClick(View v) { 27 // ダイアログ表示 28 mPrgDlg.show(); 29 30 // スレッド生成・実行 31 mThread = new Thread(runnable); 32 mThread.start(); 33 } 34 }); 35 } 36 37 /** 38 * スレッド処理 39 */ 40 Runnable runnable = new Runnable() { 41 @Override 42 public void run() { 43 try { 44 for (int i = 0; i < 100; i++) { 45 Thread.sleep(100); 46 mPrgDlg.setProgress(i + 1); 47 } 48 49 Message msg = new Message(); 50 msg.arg1 = 0; 51 handler.sendMessage(msg); 52 } catch (InterruptedException e) { 53 e.printStackTrace(); 54 } 55 } 56 }; 57 58 /** 59 * スレッドの終了を受信するハンドラ 60 */ 61 private Handler handler = new Handler() { 62 @Override 63 public void handleMessage(Message msg) { 64 // 実行中ダイアログを閉じる 65 mPrgDlg.dismiss(); 66 Toast.makeText(MainActivity.this, "遅延ボタンが押されました", Toast.LENGTH_LONG).show(); 67 } 68 }; 69 70 @Override 71 public void onPause() { 72 super.onPause(); 73 if (mPrgDlg != null) { 74 mPrgDlg.dismiss(); // ProgressDialogも消すならこれも必要 75 } 76 if (mThread != null) { 77 mThread.interrupt(); 78 mThread = null; 79 } 80 } 81} 82

runnableの実装の中で、try-catchで囲む範囲を変えています。例外が発生したら、forループの外側に飛ぶようになっています。

onPause()が呼ばれたら、Threadを止めるためにinterruput()を実行して割り込みを飛ばしています。これにより、別スレッドとして動作しているrunnableにInterruptedExceptionが飛び、ループの外に脱出します。これによってhandler.sendMessage()も呼ばれませんので、Toastが表示されることもなくなります。

こんな感じでどうでしょうか?


別解として、Threadを使わず遅延処理にHandler#postDelayed()を用いて、質問の目的通りHandler#removeCallbacks()によって取り消す例も記します。このように、Handlerに結びついている処理ならばremoveCallbacks()によって取り消せます。

Java

1public class MainActivity extends AppCompatActivity { 2 /** 3 * プログレスバー 4 */ 5 private ProgressDialog mPrgDlg; 6 public final int minutes = 600; 7 private int count; 8 9 @Override 10 public void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.activity_main); 13 14 // 実行中ダイアログの生成・初期化 15 mPrgDlg = new ProgressDialog(this); 16 mPrgDlg.setTitle("スレッド実行中"); 17 mPrgDlg.setMessage("しばらくお待ちください。"); 18 mPrgDlg.setIndeterminate(false); 19 mPrgDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER); 20 mPrgDlg.setMax(100); // 最大値 21 mPrgDlg.incrementProgressBy(0); // 初期値 22 23 // ボタンクリック処理 24 Button btnStart = (Button) findViewById(R.id.btn); 25 btnStart.setOnClickListener(new View.OnClickListener() { 26 public void onClick(View v) { 27 // ダイアログ表示 28 mPrgDlg.show(); 29 30 count = 0; 31 // 100ミリ秒後に実行する処理を登録(初回) 32 handler.postDelayed(runnable, 100); 33 } 34 }); 35 } 36 37 /** 38 * スレッド処理 39 */ 40 Runnable runnable = new Runnable() { 41 @Override 42 public void run() { 43 count++; 44 mPrgDlg.setProgress(count); 45 46 if (count < 100) { 47 // countが目的の回数未満なら、100ミリ秒後にこの処理を再実行するように登録 48 handler.postDelayed(this, 100); 49 } else { 50 Message msg = new Message(); 51 msg.arg1 = 0; 52 handler.sendMessage(msg); 53 } 54 } 55 }; 56 57 /** 58 * スレッドの終了を受信するハンドラ 59 */ 60 private Handler handler = new Handler() { 61 @Override 62 public void handleMessage(Message msg) { 63 // 実行中ダイアログを閉じる 64 mPrgDlg.dismiss(); 65 Toast.makeText(MainActivity.this, "遅延ボタンが押されました", Toast.LENGTH_LONG).show(); 66 } 67 }; 68 69 @Override 70 public void onPause() { 71 super.onPause(); 72 if (mPrgDlg != null) { 73 mPrgDlg.dismiss(); // ProgressDialogも消すならこれも必要 74 } 75 handler.removeCallbacks(runnable); // postDelayed()で登録されている処理を取り消し 76 } 77}

投稿2018/04/29 09:22

編集2018/04/30 17:13
keicha_hrs

総合スコア6766

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mercurian-teto

2018/07/03 07:18

返信遅れてすいません。 参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問