我是Android和Java开发的初学者,我目前正在尝试制作一个节拍器。 在让声音播放工作之后我遇到的第一个问题是,每当节拍器播放应用程序时都会停止响应 - 当我了解线程以及我应该如何使用新线程进行音频播放时。
创建一个新线程帮助,现在应用程序运行正常,但我无法让线程停止/中断。我已经阅读了50篇关于线程和中断的文章,我无法弄明白。
这是我的'播放器'类代码,我大部分都是从另一个Stack Overflow帖子中复制过来的(我尝试了无数其他方法和变体,但都没有用):
package com.example.t.firstapp;
import android.util.Log;
public class Player implements Runnable {
Thread backgroundThread;
Metronome m;
public void start() {
if (backgroundThread == null) {
backgroundThread = new Thread(this);
m = new Metronome();
backgroundThread.start();
}
}
public void stop() {
if (backgroundThread != null) {
backgroundThread.interrupt();
}
}
public void run() {
try {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
}
Log.i("b", "Thread stopping.");
throw new InterruptedException(); // ???
} catch (InterruptedException ex) {
// important you respond to the InterruptedException and stop processing
// when its thrown! Notice this is outside the while loop.
Log.i("c", "Thread shutting down as it was requested to stop.");
} finally {
backgroundThread = null;
}
}
}
注意标有" ???"的行。我自己添加了一个,因为否则" catch(InterruptedException ex)"返回错误。 以下是我的MainActivity类中的相关代码:
public class MainActivity extends AppCompatActivity {
...
public Player p;
...
public void play() {
p = new Player();
p.start();
}
public void stop() {
p.stop();
}
}
调用p.stop();从方法中停止'实际上并没有做任何事情。这是我被卡住的地方。如果我在启动线程后立即调用p.stop(),如下所示:
public void play() {
p = new Player();
p.start();
p.stop();
}
然后它工作,我看到来自Player类的所有相关日志消息。当我从我的“停止”中调用它时,为什么没有p.stop()工作?方法?是因为我是用不同的方法调用它,还是因为我没有立即调用它?
任何帮助都会非常感激,因为这非常令人沮丧。我一直在研究和练习Android开发仅一周,但过去5天我没有做任何事情,但试图解决这个问题。感谢
答案 0 :(得分:2)
你误解了中断的概念。中断不是迫使线程停止的一种神奇方式,而是仅适用于有中断支持的方法 - 比如睡觉。
查看Thread#interrupt()
API,其中列出了中断支持的方法:
如果在调用
wait()
t类的wait(long)
,wait(long, int)
或Objec
方法或join()
方法时阻止此线程,join(long)
,join(long, int)
,sleep(long)
或sleep(long, int)
这个类的方法,然后它的中断状态将被清除,它将收到InterruptedException
。< / p>如果此线程在可中断通道的I / O操作中被阻止,则通道将关闭,线程的中断状态将被设置,并且线程将收到
ClosedByInterruptException
。如果此线程在
Selector
中被阻止,则线程的中断状态将被设置,并且它将立即从选择操作返回,可能具有非零值,就像选择器& #39;唤醒方法被调用。如果以前的条件都不成立,那么将设置此线程的中断状态。
通过检测中断状态,您可以通过中断支持很好地实现自己的方法。
现在让我们看看我们如何解决您的问题。
根据你的评论,m.play()
没有返回,这意味着,一旦m.play()
被调用,while
永远不会检查线程是否被中断;反过来它永远不会停止,因为m.play()
并未实现以支持中断。这也应该解释为什么编译器抱怨没有人抛出InterruptedException
。 (如果立即中断它起作用的原因是中断状态在到达while
之前改变了......想一想。)
现在,我认为,如果您致电m.stop()
,m.play()
将返回,成功重新检查线程中断。正如评论中所提到的那样,这就是它起作用的原因。
但是看,没有真正使用中断线程 - 因为你要做的就是调用m.stop()
并释放m.play()
,只是玩并等待返回 - 这意味着停止已被召唤。与while
循环相同,将其全部删除。
public void run() {
Log.i("a", "Thread starting.");
m.play(); // blocks till stopped from some other thread...
Log.i("b", "Thread stopping.");
Log.i("c", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}
我可能会看到使用while
和中断的情况,如果m.play()
可能早于调用m.stop()
(例如,通过某种例外)返回,并且您希望重启节拍器直到调用停止;然后一个循环可能正在拯救,并且中断可能通过调用m.stop()
发出信号表明它实际上已停止。
public void run() {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
if(!backgroundThread.isInterrupted())
Log.i("b", "Stopped by exception, restarting....");
}
Log.i("c", "Thread stopping.");
Log.i("d", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}