Androidでスレッドを停止する最適な方法を知りたいです。代わりにAsyncTask
を使用でき、cancel()
メソッドがあることを知っています。私の状況ではThread
sを使用する必要があります。 Thread
の使用方法は次のとおりです。
Runnable runnable = new Runnable() {
@Override
public void run() {
//doing some work
}
};
new Thread(runnable).start();
だから、誰もスレッドを停止するための最良の方法であるという考えを持っていますか?
スレッドが割り込みをサポートするようにする必要があります。基本的に、yourThread.interrupt()
を呼び出してスレッドを停止し、run()メソッドでThread.interrupted()
のステータスを定期的に確認する必要があります。
良いチュートリアルがあります こちら 。
この状況は、標準のJavaとまったく変わりません。標準的な方法でスレッドを停止できます:
class WorkerThread extends Thread {
volatile boolean running = true;
public void run() {
// Do work...
if (!running) return;
//Continue doing the work
}
}
主なアイデアは、時々フィールドの値をチェックすることです。スレッドを停止する必要がある場合は、running
をfalseに設定します。また、Chrisが指摘したように、中断メカニズムを使用できます。
ちなみに、AsyncTaskを使用する場合は、アプローチに大きな違いはありません。唯一の違いは、特別なフィールドを持つ代わりに、タスクからisCancel()
メソッドを呼び出す必要があることです。 cancel(true)
を呼び出しても、このメカニズムを実装しないと、スレッドはそれ自体で停止せず、最後まで実行されます。
Androidでは、通常のJava環境と同じルールが適用されます。 Javaでは、スレッドは強制終了されませんが、スレッドの停止は協力的な方法で行われます。スレッドは終了するように要求され、スレッドは正常にシャットダウンできます。
多くの場合、volatile boolean
フィールドが使用されます。このフィールドは、対応する値に設定されると、スレッドが定期的にチェックして終了します。
Inot notboolean
を使用して、スレッドが終了する必要があるかどうかを確認しますterminate。 volatile
をフィールド修飾子として使用すると、これは信頼性の高い動作をしますが、コードがより複雑になると、代わりにwhile
ループ内で他のブロックメソッドを使用するため、コードが終了しないまたは少なくとも時間がかかります。
特定のブロッキングライブラリメソッドは割り込みをサポートします。
すべてのスレッドには、すでにブール値フラグ割り込みステータスがあり、それを利用する必要があります。次のように実装できます。
public void run() {
try {
while(!Thread.currentThread().isInterrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
Java同時実行性の実践 から取得したソースコード。 cancel()
メソッドはパブリックなので、必要に応じて別のスレッドにこのメソッドを呼び出させることができます。
また、現在のスレッドの中断状態をクリアする、名前の不十分な静的メソッドinterrupted
もあります。
スレッドを停止するために使用できる Thread.stop()
メソッドは廃止されました。詳細については、 なぜThread.stop、Thread.suspend、およびThread.resumeは非推奨ですか? 。
最善の策は、スレッド自体が参照する変数を用意し、変数が特定の値と等しい場合に自発的に終了することです。次に、スレッドを終了するときにコード内の変数を操作します。もちろん、代わりに AsyncTask
を使用することもできます。
問題は、スレッドが実行中かどうか!?かどうかを確認する必要があることです。
フィールド:
private boolean runningThread = false;
スレッド内:
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep((long) Math.floor(speed));
if (!runningThread) {
return;
}
yourWork();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
スレッドを停止する場合は、以下のフィールドを作成する必要があります
private boolean runningThread = false;
現在、残念ながら、スレッドを停止することはできません。
Mattの答えに何かを追加すると、interrupt()
を呼び出すことができますが、それはスレッドを停止しません...システムがスレッドを強制終了したいときにスレッドを停止するようにシステムに指示します。残りはシステムによって行われ、interrupted()
を呼び出すことで確認できます。
[追伸:interrupt()
を本当に使用する場合は、interrupt()
]を呼び出した後、短いスリープでいくつかの実験を行うようにお願いします
スレッドを停止するには、次の2つの方法をお勧めします。
揮発性ブール変数を作成し、その値をfalseに変更して、スレッド内をチェックします。
volatile isRunning = false;
public void run(){if(!isRunning){return;}}
または、スレッド内で受信できるinterrupt()メソッドを使用できます。
SomeThread.interrupt();
public void run(){if(Thread.currentThread.isInterrupted()){return;}}
この方法を使用しました。
Looper.myLooper().quit();
あなたが試すことができます。
プロジェクト内にハンドラーを持つスレッドクラスがある場合、フラグメントクラスの1つから開始したときにここで停止したい場合は、フラグメントがスタックから削除されたときにアプリを停止してクラッシュを回避する方法です。
このコードはKotlinにあります。それは完全に機能します。
class NewsFragment : Fragment() {
private var mGetRSSFeedsThread: GetRSSFeedsThread? = null
private val mHandler = object : Handler() {
override fun handleMessage(msg: Message?) {
if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
val updateXMLdata = msg.obj as String
if (!updateXMLdata.isNullOrEmpty())
parseUpdatePager(CommonUtils.getJSONObjectFromXML(updateXMLdata).toString())
} else if (msg?.what == GetRSSFeedsThread.GETRSSFEEDSTHREAD_SUCCESS) {
BaseActivity.make_toast(activity, resources.getString(R.string.pleaseTryAgain))
}
}
}
private var rootview: View? = null;
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
rootview = inflater?.inflate(R.layout.fragment_news, container, false);
news_listView = rootview?.findViewById(R.id.news_listView)
mGetRSSFeedsThread = GetRSSFeedsThread(this.activity, mHandler)
if (CommonUtils.isInternetAvailable(activity)) {
mGetRSSFeedsThread?.start()
}
return rootview
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true);
}
override fun onAttach(context: Context?) {
super.onAttach(context)
println("onAttach")
}
override fun onPause() {
super.onPause()
println("onPause fragment may return to active state again")
Thread.interrupted()
}
override fun onStart() {
super.onStart()
println("onStart")
}
override fun onResume() {
super.onResume()
println("onResume fragment may return to active state again")
}
override fun onDetach() {
super.onDetach()
println("onDetach fragment never return to active state again")
}
override fun onDestroy() {
super.onDestroy()
println("onDestroy fragment never return to active state again")
//check the state of the task
if (mGetRSSFeedsThread != null && mGetRSSFeedsThread?.isAlive!!) {
mGetRSSFeedsThread?.interrupt();
} else {
}
}
override fun onDestroyView() {
super.onDestroyView()
println("onDestroyView fragment may return to active state again")
}
override fun onStop() {
super.onStop()
println("onStop fragment may return to active state again")
}
}
上記のコードは、現在のフラグメントから他のフラグメントまたはアクティビティに切り替えると、実行中のスレッドを停止します。また、現在のフラグメントに戻ると再作成されます
このようにしてみてください
Thread thread = new Thread() {
@Override
public void run() {
Looper.prepare();
while(true){
Log.d("Current Thread", "Running");
try{
Thread.sleep(1000);
}catch(Exeption Ex){ }
}
}
}
thread.start();
thread.interrupt();
これは私のためにこのように働いた。メインアクティビティに静的変数を導入し、以下の方法で定期的にチェックします。
public class MainActivity extends AppCompatActivity {
//This is the static variable introduced in main activity
public static boolean stopThread =false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread thread = new Thread(new Thread1());
thread.start();
Button stp_thread= findViewById(R.id.button_stop);
stp_thread.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View v){
stopThread = true;
}
}
}
class Thread1 implements Runnable{
public void run() {
// YOU CAN DO IT ON BELOW WAY
while(!MainActivity.stopThread) {
Do Something here
}
//OR YOU CAN CALL RETURN AFTER EVERY LINE LIKE BELOW
process 1 goes here;
//Below method also could be used
if(stopThread==true){
return ;
}
// use this after every line
process 2 goes here;
//Below method also could be used
if(stopThread==true){
return ;
}
// use this after every line
process 3 goes here;
//Below method also could be used
if(stopThread==true){
return ;
}
// use this after every line
process 4 goes here;
}
}
}