2012-03-20 45 views
6

我正在学习如何在Android中使用线程,并且为此做了一个播放一系列笔记的小应用程序。这个想法是有一个开始按钮和一个结束按钮,而且(很明显),如果你按下开始按钮开始播放音乐,并且按下结束按钮,它就会停止。开始按钮工作得很好,但问题是,结束按钮没有。我无法弄清楚为什么,所以也许你们中的一些人可以帮助我。这是代码:线程不会中断

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; 
    } 
} 

回答

7

要调用播放线程interrupt()但它可能是在sleep的时间等待。这会抓住睡觉扔一个InterruptedException。您需要捕获该异常退出循环停止播放:

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

由于interrupt()也可以来在不同的时间,你需要测试中断状态,退出你的循环:

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

另外,两个线程之间共享的所有变量都需要为​​或标记为volatile。该paused标志大概应该是volatile这里:

volatile boolean paused = false 

最后,留给后人,当你抓住InterruptedException,它会清除线程的中断状态。通常很好的做法是立即在线程上设置中断标志,以便其他人可以测试它:

try { 
     Thread.sleep(NOTE_DURATION); 
    } catch (InterruptedException e) { 
     // re-establish the interrupt condition 
     Thread.currentThread.interrupt(); 
     ... 
    } 
+0

它工作!感谢您的帮助:] – Zero 2012-03-20 19:40:16

+0

我没有得到最后一点,执行'return;'和重新建立中断条件有什么区别。 – 2015-10-19 13:53:25

+1

每当你捕捉到'InterruptedException'时,线程上的中断状态就会被清除,所以你应该重新中断线程。这是一个重要的模式,所以如果你的代码在库中,调用者会被通知线程被中断。这只是我一直提到的模式@MuhammedRefaat。 – Gray 2015-10-19 14:38:55