这个问题实际上只是出于纯粹的好奇心。我已经找到了一个解决方法,如果有人有兴趣,我会在问题的最后解释。
我有一个运行后台线程的Android应用程序。我想在用户按下电源键时中断该线程。为了实现这一点,我使用了这样的BroadcastReceiver:
public Class MyService extends Service {
private MyThread myThread;
//https://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
private class ScreenReceiver extends BroadcastReceiver {
boolean wasScreenOn = true;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.d(TAG, "Power key!");
myThread.interrupt();
wasScreenOn = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
wasScreenOn = true;
}
}
}
private Class MyThread extends Thread {
private MyObject myObject;
//various thread functions
public void run(){
while(!isInterrupted()){
//I have code here that waits for the user to let us know to start
myObject = new MyObject();
myObject.foo();
}
}
}
public void onCreate(){
//various setup steps
myThread = new MyThread();
myThread.start(); //myThread.run() will get called by this
}
}
不幸的是,仅仅中断线程是不够的,因为它不会频繁地轮询中断:线程包含一个对象(MyObject)的实例,它正在运行一个函数(foo),我可以' t轮询线程上的中断,直到foo完成。为了解决这个问题,我在MyObject类中实现了一个标志,我可以在foo中检查并在必要时中断函数(就像Thread.interrupt如何工作,除了MyObject不扩展Thread)
public class MyObject {
//other variables
private boolean isInterrupted;
public MyObject(){
//various setup
isInterrupted = false;
}
public boolean foo() {
while(!isInterrupted){
//doStuff, return true or false if finished
}
return false;
}
public void setInterruptFlag(){
isInterrupted = true;
}
}
有了这个,我在MyThread中覆盖了中断方法:
public void interrupt(){
Log.d(TAG, "Interrupted!");
if(myObject != null)
myObject.setInterruptFlag();
super.interrupt();
}
这会停止函数foo并且或多或少地执行我想要的操作。但是,下次从myThread.run()调用myObject.foo()时,myThread.interrupt()会在早期被调用,整个事情就会停止。之后的下一次运行恢复正常。
查看日志输出,我只看到“电源键!”关闭屏幕时打印输出(如预期的那样)。但是,“中断!”打印输出快速连续发生4或5次,然后在用户重新启动线程时再次发生。我称之为myThread.interrupt()的唯一地方就是“电源键”!日志声明,所以我很困惑额外的电话来自哪里。系统是否会在某些地方自动调用中断,如果是,为什么?
我提到的解决方法是完全删除对myThread.interrupt的调用,而只是扩展myObject的范围,以便我可以直接从BroadcastReceiver调用myObject.setInterruptFlag()