views:

1773

answers:

3

My service spawns a new thread, and stops it according to the typically recommended java method of interrupt()'ing. When I stop the service, I stop the thread in onDestroy(). The service is stopped, and the interrupt code is reached. However, soon enough the thread restarts from the beginning of the Runnable.

public class DoScan extends Service {
 public volatile Thread runner;

 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }

 @Override
 public void onCreate() {
  super.onCreate();

  startThread();
 }

 @Override
 public void onDestroy() {
  super.onDestroy();
  android.util.Log.v("@@@@@@@@@@@@@@@@@@@@", "DoScan.onDestroy");
  stopThread();
 }


 public synchronized void startThread(){
  if(runner == null){
   android.util.Log.v("@@@@@@@@@@@@@@@@@@@@", "DoScan.startthread");   
   runner = new Thread(new ScanningThread());
   runner.start();
  }
 }
 /* use a handler in a loop cycling through most of oncreate.
  * the scanningthread does the work, then notifies the svc's uithread
  */

 public synchronized void stopThread(){
  if(runner != null){
   android.util.Log.v("@@@@@@@@@@@@@@@@@@@@", "DoScan.stopthread");
   Thread moribund = runner;
   runner = null;
   moribund.interrupt();
   android.util.Log.v("@@@@@@@@@@@@@@@@@@@@", "interrupted?" + moribund.isInterrupted());
  }
 }
        }
A: 

Interrupting a thread throws an exception in the thread, it does not necessarily stop it. You should catch that exception and then do the clean up in thread before exiting (provided, you need to exit!).

Prashast
Actually, it doesn't throw an exception. Some calls will throw an exception back if they detect that they have been interrupted but in most cases you will have to do the detection yourself by checking Thread.isInterrupted() when it is suitable to interrupt the work.
Fredrik
+3  A: 

Hello,

I think the safest way is to have a flag so the thread checks for it inside its main loop.

class ScanningThread extends Thread {
 // Must be volatile:
 private volatile boolean stop = false;

 public void run() {
  while (!stop) {
   System.out.println("alive");
  }
  if (stop)
   System.out.println("Detected stop");
 }

 public synchronized void requestStop() {
  stop = true;
 }
}

public synchronized void startThread(){
 if(runner == null){
  android.util.Log.v("@@@@@@@@@@@@@@@@@@@@", "DoScan.startthread");         
  runner = new ScanningThread();
  runner.start();
 }
}

public synchronized void stopThread(){
 if(runner != null){
  android.util.Log.v("@@@@@@@@@@@@@@@@@@@@", "DoScan.stopthread");
  runner.requestStop();
  runner = null;
 }
}
Lucas S.
+1  A: 

The problem is that your thread needs to cooperate by periodically checking for interruption and exiting if the thread has been interrupted. Unless you place something along the lines of the following in your thread...

 // Processing...
 if ( Thread.interrupted() ){
    return;
 }
 // More processing...
 try{
    Thread.sleep(sleeptime);
 }catch(InterruptedException interrupt){
    return;
 }
 // Rinse and repeat...

...your thread will just ignore the fact that it has been interrupted. The method proposed by Lucas S. is essentially identical, except that using interruption will generate an exception if the thread is blocked, whereas under Lucas S.'s method, you might have to wait indefinitely for the thread to quit.

Michael Aaron Safyan