Android - лучший и безопасный способ остановить поток - PullRequest
74 голосов
/ 14 декабря 2011

Я хочу знать, какой лучший способ остановить поток в Android. Я знаю, что могу использовать AsyncTask вместо него и что есть метод cancel(). Я должен использовать Thread с в моей ситуации. Вот как я использую Thread:

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

Итак, кто-нибудь имеет представление о том, что является лучшим способом остановить поток?

Ответы [ 12 ]

80 голосов
/ 14 декабря 2011

Вы должны сделать прерывания поддержки вашего потока. По сути, вы можете вызвать yourThread.interrupt(), чтобы остановить поток, и в вашем методе run () вам необходимо периодически проверять состояние Thread.interrupted()

Здесь есть хороший учебник .

27 голосов
/ 14 декабря 2011

Эта ситуация ничем не отличается от стандартной Java. Вы можете использовать стандартный способ остановить поток:

class WorkerThread extends Thread {
    volatile boolean running = true;

    public void run() {
        // Do work...
        if (!running) return;
        //Continue doing the work
    }
}

Основная идея - проверять значение поля время от времени. Когда вам нужно остановить поток, вы устанавливаете running в false. Также, как указал Крис, вы можете использовать механизм прерывания.

Кстати, когда вы используете AsyncTask, ваше приложение не будет сильно отличаться. Единственное отличие состоит в том, что вам придется вызывать метод isCancel() из вашей задачи вместо того, чтобы иметь специальное поле. Если вы вызываете cancel(true), но не реализуете этот механизм, поток все равно не остановится сам по себе, он будет работать до конца.

18 голосов
/ 20 мая 2014

В Android применяются те же правила, что и в обычной среде Java. В Java потоки не уничтожаются, но остановка потока выполняется кооперативным способом . Поток просят прекратить, и затем поток может корректно завершиться.

Часто используется поле volatile boolean, которое поток периодически проверяет и завершает, когда ему присваивается соответствующее значение.

I не будет использовать boolean, чтобы проверить, должен ли поток завершить . Если вы используете volatile в качестве модификатора поля, это будет работать надежно, но если ваш код становится более сложным, так как вместо этого используются другие методы блокировки внутри цикла while, может случиться, что ваш код не прекратит работу вообще или, по крайней мере, занимает больше времени , как вы можете.

Некоторые методы блокировки библиотеки поддерживают прерывание.

Каждый поток уже имеет логический флаг Прерванный статус , и вы должны использовать его. Это может быть реализовано так:

public void run() {

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

}

public void cancel() { interrupt(); }

Исходный код взят из Java-параллелизма на практике . Поскольку метод cancel() является общедоступным, вы можете позволить другому потоку вызывать этот метод так, как вам нужно.

Существует также статический метод со слабым названием interrupted, который очищает прерванный статус текущего потока.

15 голосов
/ 14 декабря 2011

Метод Thread.stop(), который можно использовать для остановки потока, устарел; для получения дополнительной информации см; Почему Thread.stop, Thread.suspend и Thread.resume устарели? .

Лучше всего иметь переменную, к которой обращается сам поток, и добровольно выходить из нее, если переменная равна определенному значению. Затем вы манипулируете переменной внутри вашего кода, когда хотите, чтобы поток завершился. В качестве альтернативы вы можете использовать AsyncTask.

2 голосов
/ 06 июня 2017

Дело в том, что вам нужно проверить, работает ли поток или нет !?

Поле:

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 голосов
/ 14 декабря 2011

В настоящее время, к сожалению, мы не можем ничего сделать, чтобы остановить поток ....

Добавляя что-то к ответу Мэтта, мы можем назвать interrupt(), но это не останавливает поток ... Просто говорит системе остановить поток, когда система хочет уничтожить некоторые потоки. Отдых делается системой, и мы можем проверить это, позвонив по номеру interrupted().

[p.s. : Если вы действительно используете interrupt(), я бы попросил вас сделать несколько экспериментов с коротким сном после вызова interrupt()]

1 голос
/ 30 ноября 2017

Есть 2 способа остановить поток.

  1. Создайте переменную логической переменной, измените ее значение на false и проверьте внутри потока.

    volatile isRunning = false;

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

  2. Или вы можете использовать метод interrupt (), который можно получить внутри потока.

    SomeThread.interrupt ();

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

0 голосов
/ 03 мая 2019

Попробуйте, как это

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 голосов
/ 16 августа 2018

Если в вашем проекте есть класс потока с обработчиком, то, когда вы начали с одного из класса фрагмента, если вы хотите остановиться здесь, это решение, как остановить и избежать сбоя приложения, когда фрагмент удаляется из стека.*

Этот код находится в 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 голосов
/ 30 января 2018

Это сработало для меня так. Введите статическую переменную в основной вид деятельности и регулярно проверяйте ее, как я делал ниже.

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;



       }
   }

}
...