web-dev-qa-db-ja.com

Android-スレッドを停止するための最良かつ安全な方法

Androidでスレッドを停止する最適な方法を知りたいです。代わりにAsyncTaskを使用でき、cancel()メソッドがあることを知っています。私の状況ではThreadsを使用する必要があります。 Threadの使用方法は次のとおりです。

Runnable runnable = new Runnable() {
        @Override
        public void run() {
            //doing some work
        }
    };
new Thread(runnable).start();

だから、誰もスレッドを停止するための最良の方法であるという考えを持っていますか?

75
Android-Droid

スレッドが割り込みをサポートするようにする必要があります。基本的に、yourThread.interrupt()を呼び出してスレッドを停止し、run()メソッドでThread.interrupted()のステータスを定期的に確認する必要があります。

良いチュートリアルがあります こちら

81
Chris

この状況は、標準の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)を呼び出しても、このメカニズムを実装しないと、スレッドはそれ自体で停止せず、最後まで実行されます。

27
Malcolm

Androidでは、通常のJava環境と同じルールが適用されます。 Javaでは、スレッドは強制終了されませんが、スレッドの停止は協力的な方法で行われます。スレッドは終了するように要求され、スレッドは正常にシャットダウンできます。

多くの場合、volatile booleanフィールドが使用されます。このフィールドは、対応する値に設定されると、スレッドが定期的にチェックして終了します。

Inot notbooleanを使用して、スレッドが終了する必要があるかどうかを確認しますterminatevolatileをフィールド修飾子として使用すると、これは信頼性の高い動作をしますが、コードがより複雑になると、代わりにwhileループ内で他のブロックメソッドを使用するため、コードが終了しないまたは少なくとも時間がかかります

特定のブロッキングライブラリメソッドは割り込みをサポートします。

すべてのスレッドには、すでにブール値フラグ割り込みステータスがあり、それを利用する必要があります。次のように実装できます。

public void run() {

   try {
      while(!Thread.currentThread().isInterrupted()) {
         // ...
      }
   } catch (InterruptedException consumed)
      /* Allow thread to exit */
   }

}

public void cancel() { interrupt(); }

Java同時実行性の実践 から取得したソースコード。 cancel()メソッドはパブリックなので、必要に応じて別のスレッドにこのメソッドを呼び出させることができます。

また、現在のスレッドの中断状態をクリアする、名前の不十分な静的メソッドinterruptedもあります。

18
Konrad Reiche

スレッドを停止するために使用できる Thread.stop() メソッドは廃止されました。詳細については、 なぜThread.stop、Thread.suspend、およびThread.resumeは非推奨ですか?

最善の策は、スレッド自体が参照する変数を用意し、変数が特定の値と等しい場合に自発的に終了することです。次に、スレッドを終了するときにコード内の変数を操作します。もちろん、代わりに AsyncTask を使用することもできます。

15
Matt

問題は、スレッドが実行中かどうか!?かどうかを確認する必要があることです。

フィールド:

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;
2
Hadi Note

現在、残念ながら、スレッドを停止することはできません。

Mattの答えに何かを追加すると、interrupt()を呼び出すことができますが、それはスレッドを停止しません...システムがスレッドを強制終了したいときにスレッドを停止するようにシステムに指示します。残りはシステムによって行われ、interrupted()を呼び出すことで確認できます。

[追伸:interrupt()を本当に使用する場合は、interrupt()]を呼び出した後、短いスリープでいくつかの実験を行うようにお願いします

2
Prasham

スレッドを停止するには、次の2つの方法をお勧めします。

  1. 揮発性ブール変数を作成し、その値をfalseに変更して、スレッド内をチェックします。

    volatile isRunning = false;

    public void run(){if(!isRunning){return;}}

  2. または、スレッド内で受信できるinterrupt()メソッドを使用できます。

    SomeThread.interrupt();

    public void run(){if(Thread.currentThread.isInterrupted()){return;}}

1
Suresh Sharma

この方法を使用しました。

Looper.myLooper().quit();

あなたが試すことができます。

0
Yanchao Wang

プロジェクト内にハンドラーを持つスレッドクラスがある場合、フラグメントクラスの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")



    }
}

上記のコードは、現在のフラグメントから他のフラグメントまたはアクティビティに切り替えると、実行中のスレッドを停止します。また、現在のフラグメントに戻ると再作成されます

0

このようにしてみてください

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();
0
Udara Kasun

これは私のためにこのように働いた。メインアクティビティに静的変数を導入し、以下の方法で定期的にチェックします。

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;



       }
   }

}
0
Seyon Seyon