Chcę wiedzieć, jaki jest najlepszy sposób na zatrzymanie wątku w systemie Android. Wiem, że mogę AsyncTask
zamiast tego użyć i że jest cancel()
metoda. Muszę użyć Thread
s w mojej sytuacji. Oto jak używam Thread
:
Runnable runnable = new Runnable() {
@Override
public void run() {
//doing some work
}
};
new Thread(runnable).start();
Więc czy ktoś ma pomysł, który jest najlepszy sposób na zatrzymanie wątku?
android
thread-safety
Android-Droid
źródło
źródło
stop()
Metoda @ MilošČernilovský jest przestarzała i nie należy jej już używać.Ta sytuacja nie różni się w żaden sposób od standardowej Java. Możesz użyć standardowego sposobu zatrzymania wątku:
class WorkerThread extends Thread { volatile boolean running = true; public void run() { // Do work... if (!running) return; //Continue doing the work } }
Głównym pomysłem jest od czasu do czasu sprawdzanie wartości pola. Kiedy musisz zatrzymać wątek, ustawiasz
running
na fałsz. Ponadto, jak zauważył Chris, możesz skorzystać z mechanizmu przerywania.Nawiasem mówiąc, gdy używasz AsyncTask, twoje apporach nie będą się zbytnio różnić. Jedyną różnicą jest to, że będziesz musiał wywołać
isCancel()
metodę ze swojego zadania, zamiast mieć specjalne pole. Jeśli wywołaszcancel(true)
, ale nie zaimplementujesz tego mechanizmu, wątek nadal nie zatrzyma się samoczynnie, będzie działał do końca.źródło
W systemie Android obowiązują te same zasady, co w normalnym środowisku Java. W Javie wątki nie są zabijane, ale zatrzymywanie wątku odbywa się w sposób kooperacyjny . Wątek jest proszony o zakończenie, a następnie można go bezpiecznie zamknąć.
Często
volatile boolean
używane jest pole, które wątek okresowo sprawdza i kończy się, gdy zostanie ustawiona na odpowiednią wartość.Nie użyłbym a
boolean
do sprawdzenia, czy wątek powinien się zakończyć . Jeśli użyjeszvolatile
jako modyfikatora pola, będzie to działać niezawodnie, ale jeśli twój kod stanie się bardziej złożony, ponieważ zamiast tego użyjesz innych metod blokujących wewnątrzwhile
pętli, może się zdarzyć, że twój kod w ogóle się nie zakończy lub przynajmniej zajmie więcej czasu . może chcieć.Każdy wątek ma już stan przerwania flagi boolowskiej i powinieneś to wykorzystać. Można to zaimplementować w następujący sposób:
public void run() { try { while(!Thread.currentThread().isInterrupted()) { // ... } } catch (InterruptedException consumed) /* Allow thread to exit */ } } public void cancel() { interrupt(); }
Kod źródłowy pobrany z Java Concurrency in Practice . Ponieważ
cancel()
metoda jest publiczna, możesz pozwolić innemu wątkowi wywołać tę metodę, jak chcesz.Istnieje również słabo nazwana metoda statyczna,
interrupted
która czyści stan przerwania bieżącego wątku.źródło
if (Thread.interrupted()) { throw new InterruptedException();}
Thread.stop()
Metody, które mogą być stosowane do zatrzymania nić została zastąpiona; aby uzyskać więcej informacji, zobacz; Dlaczego Thread.stop, Thread.suspend i Thread.resume są przestarzałe? .Najlepszym rozwiązaniem jest posiadanie zmiennej, z którą sam wątek konsultuje się i dobrowolnie wychodzi, jeśli zmienna ma określoną wartość. Następnie manipulujesz zmienną w kodzie, gdy chcesz, aby wątek został zamknięty. Oczywiście możesz też
AsyncTask
zamiast tego użyć pliku .źródło
Obecnie niestety nie możemy nic zrobić, aby zatrzymać wątek ....
Dodając coś do odpowiedzi Matta, możemy zadzwonić,
interrupt()
ale to nie zatrzymuje wątku ... Po prostu mówi systemowi, aby zatrzymał wątek, gdy system chce zabić niektóre wątki. Resztę wykonuje system i możemy to sprawdzić dzwoniącinterrupted()
.[ps: Jeśli naprawdę wybierasz się z
interrupt()
tobą, poproszę cię o wykonanie kilku eksperymentów z krótkim snem po telefonieinterrupt()
]źródło
Spróbuj w ten sposób
Thread thread = new Thread() { @Override public void run() { Looper.prepare(); while(true){ Log.d("Current Thread", "Running"); try{ Thread.sleep(1000); }catch(Exeption exception){ } } } }; thread.start(); thread.interrupt();
źródło
Istnieją 2 preferowane sposoby zatrzymania wątku.
Utwórz niestabilną zmienną boolowską i zmień jej wartość na false i sprawdź wewnątrz wątku.
volatile isRunning = false; public void run() { if(!isRunning) {return;} }
Lub możesz użyć metody przerwania (), która może zostać odebrana wewnątrz wątku.
SomeThread.interrupt(); public void run() { if(Thread.currentThread.isInterrupted()) {return;} }
źródło
Użyłem tej metody.
Looper.myLooper().quit();
możesz spróbować.
źródło
To zadziałało dla mnie w ten sposób. Wprowadź zmienną statyczną do głównego działania i regularnie sprawdzaj, jak to zrobiłem, poniżej.
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; } } }
źródło
Jeśli w Twoim projekcie istnieje klasa wątku z programem obsługi, to gdy zaczynasz od jednej z klas fragmentów, jeśli chcesz się tutaj zatrzymać, jest rozwiązanie, jak zatrzymać i uniknąć awarii aplikacji, gdy fragment zostanie usunięty ze stosu.
Ten kod jest w Kotlinie . Działa doskonale.
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") } }
Powyższy kod zatrzymuje działający wątek po przełączeniu na inny fragment lub aktywność z bieżącego fragmentu. również odtwarza się po powrocie do bieżącego fragmentu
źródło
Chodzi o to, że musisz sprawdzić, czy wątek działa, czy nie !?
Pole:
private boolean runningThread = false;
W wątku:
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();
Jeśli chcesz przerwać wątek, powinieneś zrobić poniższe pole
private boolean runningThread = false;
źródło
Thread
, a tylkoyourWork();
zostanie wywołane. Aby to przetestować, możesz dodaćLog
poniżejpublic void run() {
If you want to stop the thread you should make the below field: private boolean runningThread = false;
. To nie jest poprawne.Moje wymaganie było nieco inne niż pytanie, ale jest to również przydatny sposób na zatrzymanie wątku w celu wykonania jego zadań. Chciałem tylko zatrzymać wątek po wyjściu z ekranu i wznowić go podczas powrotu do ekranu.
Zgodnie z dokumentacją systemu Android byłby to proponowany zamiennik metody stop , która została wycofana z interfejsu API 15
Moja klasa Thread
class ThreadClass implements Runnable { ... @Override public void run() { while (count < name.length()) { if (!exited) // checks boolean { // perform your task } ...
OnStop i OnResume wyglądałyby tak
@Override protected void onStop() { super.onStop(); exited = true; } @Override protected void onResume() { super.onResume(); exited = false; }
źródło
Ponieważ wiemy, że Thread.stop () jest przestarzała w JAVA, pod maską Thread.stop wywołuje metodę przerwania () w wątku, aby go zatrzymać, Przerwanie ma być wyrzucane z metod, które utrzymują wątek w oczekiwaniu na inny wątek do powiadomienia po zakończeniu wykonywania. Przerwanie nie spowoduje nic w wątku, jeśli nie jest obsługiwane podczas wykonywania wątku, na przykład,
if(Thread.interrupted())return;
w sumie musimy w zasadzie zarządzać początkiem i zatrzymaniem wątku, tak jak wywołaniestart()
metody takiej jakThread.start()
zaczyna sięwhile(true)
wewnątrzrun()
metody wątku i sprawdza stan przerwania w każdej iteracji i wraca z wątku.Należy pamiętać, że wątek nie zginie w następujących sytuacjach:
źródło
Wewnątrz dowolnej klasy Activity tworzysz metodę, która przypisze NULL do instancji wątku, która może być używana jako alternatywa dla zdeprecycjonowanej metody stop () do zatrzymywania wykonywania wątku:
public class MyActivity extends Activity { private Thread mThread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mThread = new Thread(){ @Override public void run(){ // Perform thread commands... for (int i=0; i < 5000; i++) { // do something... } // Call the stopThread() method. stopThread(this); } }; // Start the thread. mThread.start(); } private synchronized void stopThread(Thread theThread) { if (theThread != null) { theThread = null; } } }
U mnie to działa bez problemu.
źródło
Thread
zmiennej nanull
nie spowoduje zatrzymania wątku. Skierowanie argumentu donull
środkastopThread
to kompletna strata czasu.