El hilo no interrumpe

Estoy aprendiendo a usar hilos en Android, y para hacer eso he hecho una pequeña aplicación que juega una serie de notas. La idea es que hay un botón de inicio y un botón de fin y que (obviamente) si presiona el botón de inicio que comienza a reproducir música, y si presiona el botón de finalización, se detiene. El botón de inicio funciona bien, pero el problema es que el botón de finalización no. Tengo problemas para averiguar por qué, así que tal vez algunos de ustedes pueden ayudarme. Este es el código:

public class PressAndPlay extends Activity { private volatile Thread initBkgdThread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button startButton = (Button) findViewById(R.id.trigger); startButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { // create thread initBkgdThread = new Thread(new Runnable() { public void run() { play_music(); } }); initBkgdThread.start(); } }); Button endButton = (Button) findViewById(R.id.end); endButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { end_music(); } }); } int[] notes = {R.raw.c5, R.raw.b4, R.raw.a4, R.raw.g4}; int NOTE_DURATION = 400; MediaPlayer m_mediaPlayer; private void play_music() { for(int ii=0; ii<12; ii++) { //check to ensure main activity is not paused if(!paused) { if (m_mediaPlayer != null) {m_mediaPlayer.release();} m_mediaPlayer = MediaPlayer.create(this, notes[ii%4]); m_mediaPlayer.start(); try { Thread.sleep(NOTE_DURATION); } catch (InterruptedException e) { e.printStackTrace(); } } } } private void end_music() { if(initBkgdThread != null) { initBkgdThread.interrupt(); initBkgdThread = null; } } boolean paused = false; @Override protected void onPause() { paused = true; super.onPause(); } @Override protected void onResume() { super.onResume(); paused = false; } } 

Usted está llamando a interrupt() en el hilo de juego, pero es probable que esté esperando en el momento de sleep . Esto atrapará el sueño para lanzar una InterruptedException . Es necesario capturar esa excepción y salir del bucle para detener la reproducción:

  try { Thread.sleep(NOTE_DURATION); } catch (InterruptedException e) { // XXX need to stop playing here, maybe return or break? return; } 

Dado que la interrupt() también puede venir en un momento diferente, es necesario probar el estado de interrupción y cerrar el bucle:

  if (!paused && !Thread.currentThread().isInterrupted()) { ... 

Además, todas las variables que se comparten entre dos subprocesos necesitan ser synchronized o marcadas como volatile . La bandera paused probablemente debería ser volatile aquí:

 volatile boolean paused = false 

Por último, para la posteridad, cuando captura InterruptedException , elimina el estado de interrupción del subproceso. Por lo general, es una buena práctica establecer inmediatamente el indicador de interrupción en el hilo para que otros puedan probarlo:

  try { Thread.sleep(NOTE_DURATION); } catch (InterruptedException e) { // re-establish the interrupt condition Thread.currentThread.interrupt(); ... } 
  • Una pregunta sobre Android runnable
  • Contexto dentro de un Runnable
  • ¿Existe ya una clase StopWatch para android y por qué no funciona mi implementación?
  • Android: obtenga tiempo hasta que Runnable se ejecute a través de Handler
  • Cómo implementar una cola de runnables
  • ¿Es esta Runnable a salvo de fugas de memoria?
  • RemoveCallbacks no se detiene runnable
  • Android: ¿Cómo puedo detener Runnable?
  • Android: Múltiples temporizadores en un ListView con manejador y ejecutables. 2 Problemas
  • Android OpenGL gameloop fuera de OnFrame
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.