Quiero saber cuál es la mejor manera de detener un hilo en Android. Sé que puedo usarlo AsyncTask
en su lugar y que hay un cancel()
método. Tengo que usar Thread
s en mi situación. Así es como lo estoy usando Thread
:
Runnable runnable = new Runnable() {
@Override
public void run() {
//doing some work
}
};
new Thread(runnable).start();
Entonces, ¿alguien tiene alguna idea de cuál es la mejor manera de detener un hilo?
android
thread-safety
Android-Droid
fuente
fuente
stop()
método @ MilošČernilovský está obsoleto y ya no debería usarlo.Esta situación no es diferente de la del estándar Java. Puede utilizar la forma estándar para detener un hilo:
class WorkerThread extends Thread { volatile boolean running = true; public void run() { // Do work... if (!running) return; //Continue doing the work } }
La idea principal es comprobar el valor del campo de vez en cuando. Cuando necesita detener su hilo, lo establece
running
en falso. Además, como ha señalado Chris, puede utilizar el mecanismo de interrupción.Por cierto, cuando usa AsyncTask, su apporach no diferirá mucho. La única diferencia es que tendrás que llamar al
isCancel()
método desde tu tarea en lugar de tener un campo especial. Si llamacancel(true)
, pero no implementa este mecanismo, el hilo aún no se detendrá por sí solo, se ejecutará hasta el final.fuente
En Android se aplican las mismas reglas que en un entorno Java normal. En Java, los hilos no se matan, pero la detención de un hilo se realiza de forma cooperativa . Se le pide al hilo que termine y el hilo puede luego cerrarse con gracia.
A menudo
volatile boolean
, se usa un campo que el hilo verifica periódicamente y termina cuando se establece en el valor correspondiente.Yo no me utilizar una
boolean
para comprobar si el hilo debe terminar . Si lo usavolatile
como un modificador de campo, esto funcionará de manera confiable, pero si su código se vuelve más complejo, ya que en su lugar usa otros métodos de bloqueo dentro delwhile
ciclo, podría suceder que su código no termine en absoluto o al menos demore más cuando podria querer.Cada hilo ya tiene un estado de interrupción de bandera booleana y debe hacer uso de él. Se puede implementar así:
public void run() { try { while(!Thread.currentThread().isInterrupted()) { // ... } } catch (InterruptedException consumed) /* Allow thread to exit */ } } public void cancel() { interrupt(); }
Código fuente tomado de Java Concurrency in Practice . Dado que el
cancel()
método es público, puede permitir que otro hilo invoque este método como desee.También hay un método estático mal nombrado
interrupted
que borra el estado interrumpido del hilo actual.fuente
if (Thread.interrupted()) { throw new InterruptedException();}
El
Thread.stop()
método que podría usarse para detener un hilo ha quedado obsoleto; para más información ver; ¿Por qué Thread.stop, Thread.suspend y Thread.resume están obsoletos? .Su mejor opción es tener una variable que el hilo mismo consulte y salga voluntariamente si la variable es igual a un cierto valor. Luego manipula la variable dentro de su código cuando desea que el hilo salga. Alternativamente, por supuesto, puede usar un
AsyncTask
.fuente
Actualmente y lamentablemente no podemos hacer nada para detener el hilo ...
Al agregar algo a la respuesta de Matt, podemos llamar,
interrupt()
pero eso no detiene el hilo ... Solo le dice al sistema que detenga el hilo cuando el sistema quiera eliminar algunos hilos. El reposo lo realiza el sistema, y podemos comprobarlo llamandointerrupted()
.[pd: si realmente vas con,
interrupt()
te pediría que hagas algunos experimentos con un poco de sueño después de llamarinterrupt()
]fuente
Prueba así
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();
fuente
Hay 2 formas siguientes preferidas para detener un hilo.
Cree una variable booleana volátil y cambie su valor a falso y verifique dentro del hilo.
volatile isRunning = false; public void run() { if(!isRunning) {return;} }
O puede usar el método interrupt () que se puede recibir dentro de un hilo.
SomeThread.interrupt(); public void run() { if(Thread.currentThread.isInterrupted()) {return;} }
fuente
Usé este método.
Looper.myLooper().quit();
puedes probar.
fuente
Esto funcionó para mí así. Introduzca una variable estática en la actividad principal y compruebe regularmente cómo lo hice a continuación.
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; } } }
fuente
Si hay una clase de subproceso con un controlador en su proyecto, cuando comenzó desde una de la clase de fragmento, si quería detenerse, aquí está la solución de cómo detener y evitar bloquear la aplicación cuando el fragmento se elimina de la pila.
Este código está en Kotlin . Funciona perfectamente.
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") } }
El código anterior detiene el hilo en ejecución cuando cambia a cualquier otro fragmento o actividad del fragmento actual. también se recrea cuando regresa al fragmento actual
fuente
¡¿Lo que necesitas es comprobar si el hilo se está ejecutando o no ?!
Campo:
private boolean runningThread = false;
En el hilo:
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();
Si desea detener el hilo, debe hacer el siguiente campo
private boolean runningThread = false;
fuente
Thread
, solo dejaráyourWork();
de ser llamado. Para probar esto, puede agregar uno aLog
continuaciónpublic void run() {
If you want to stop the thread you should make the below field: private boolean runningThread = false;
. Esto no es correcto.Mi requisito era ligeramente diferente a la pregunta, pero también es una forma útil de detener el hilo para ejecutar sus tareas. Todo lo que quería hacer era detener el hilo al salir de la pantalla y reanudarlo mientras volvía a la pantalla.
Según los documentos de Android, este sería el reemplazo propuesto para el método de detención que ha quedado obsoleto de la API 15
Mi clase de hilo
class ThreadClass implements Runnable { ... @Override public void run() { while (count < name.length()) { if (!exited) // checks boolean { // perform your task } ...
OnStop y OnResume se verían así
@Override protected void onStop() { super.onStop(); exited = true; } @Override protected void onResume() { super.onResume(); exited = false; }
fuente
Como sabemos que Thread.stop () está en desuso en JAVA, bajo el capó Thread.stop llama al método interrupt () en el hilo para detenerlo, Interrupt está destinado a ser lanzado desde los métodos que mantienen el hilo esperando algún otro hilo para notificar después de que se complete la ejecución. La interrupción no causará nada al hilo si no se maneja en la ejecución de un hilo, como,
if(Thread.interrupted())return;
Entonces, en general, básicamente necesitamos administrar el inicio y la parada del hilo como llamar alstart()
método comoThread.start()
comienzawhile(true)
dentro delrun()
método del hilo y comprueba el estado interrumpido en cada iteración y regresa del hilo.Tenga en cuenta que un hilo no morirá en las siguientes situaciones:
fuente
Dentro de cualquier clase de actividad, crea un método que asignará NULL a la instancia del hilo que se puede usar como una alternativa al método depreciado stop () para detener la ejecución del hilo:
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; } } }
Esto funciona para mí sin ningún problema.
fuente
Thread
variable ennull
no hará nada para detener el hilo. Poner el argumento en elnull
interiorstopThread
es una completa pérdida de tiempo.