Question

At a high level, the following is what I intend to happen here:

-- BroadcastReceiver within BackgroundManagerService receives a broadcast from Android (works fine)

-- BroadcastReceiver within BackgroundManagerService sends the intent to startTestsRunnerThread() (works fine)

-- startTestsRunnerThread() creates a BackgroundTestRunnerThread and starts it (seems to work fine)

-- the thread which is an instance of BackgroundTestRunnerThread and was just created is put to sleep for 60 seconds (does not work). From extensive logging, when "BackgroundTestRunnerThread.sleep(milliseconds);" is executed, it is being run within the main thread.

EDIT: I realize from the answers that sleep() is a static method and only works on the current thread. Is there a way to send a message into the thread that is running BackgroundTestRunnerThread and have it sleep (i.e., have sleep called from within the other thread)?

I realize that, as per https://stackoverflow.com/a/3072338/1783829 and other posts I should probably be doing this with ScheduledExecutorService, but that is not my question here. At the present moment, my question is about why sleep() is executing in main thread and not in a separate thread. This is causing ANR (Android Not Responding) and Android kills my app.

Here is my full code:

public class Logger {
  public static void v(String tag, String msg) {
    Log.v(tag, Thread.currentThread().getName() + " **** " + msg);
  }
}


public class BackgroundTestRunnerThread extends Thread {
    @Override
    public void run() {
      try {
        while (!BackgroundTestRunnerThread.currentThread().isInterrupted()) {
          Intent intent = new Intent(MainActivity.getAppContext(), TestsRunnerService.class);
          Logger.v(this.getClass().getName(), "About to start TestsRunnerService ");
          MainActivity.getAppContext().startService(intent);

          SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(
              MainActivity.getAppContext());
          int sleepTime;
          // Since Android saves preferences as strings, even with 'android:numeric="integer"',
          // we need to convert to an integer.
          sleepTime = Integer.parseInt(settings.getString("pref_key_frequency", "60"));
          Logger.v(this.getClass().getName(), "Sleep thread for " + sleepTime + " seconds");
          BackgroundTestRunnerThread.sleep(sleepTime * 1000);
        }
      } catch (InterruptedException e) {
        Logger.v(this.getClass().getName(), "Thread interrupted ");
      } catch (Exception e) {
        Logger.v(this.getClass().getName(), "Thread exception: " + e.getMessage());
      }
    }

    public void cancel() {
      Logger.v(this.getClass().getName(), "About to cancel thread");
      interrupt();
    }

    public void pause(int milliseconds) {
      try {
        Logger.v(this.getClass().getName(), "About to sleep thread background runner");
        // Logging shows that this is running in MAIN and not in a separate thread.
        BackgroundTestRunnerThread.sleep(milliseconds);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
}


public class BackgroundManagerService extends Service {
  private volatile BackgroundTestRunnerThread testsRunnerThread;
  private BroadcastReceiver networkStatusChangedReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        BackgroundManagerService.this.startTestsRunnerThread(60); 
    }
  };

  private void startTestsRunnerThread(int secondsDelay) {
    if (testsRunnerThread == null || !testsRunnerThread.isAlive()) {
      testsRunnerThread = new BackgroundTestRunnerThread();
      Logger.v(this.getClass().getName(), "Sending start signal to     BackgroundTestRunnerThread");
      testsRunnerThread.start();
      Logger.v(this.getClass().getName(),
          "Sending start signal to BackgroundTestRunnerThread to sleep");
      testsRunnerThread.pause(secondsDelay * 1000);
      Logger.v(this.getClass().getName(), "Executed past sleep command");
    }
  }
}

enter image description here

Était-ce utile?

La solution

As i can see you already know Thread.sleep is static method and only sleeps the current thread running there are 2 places where you are using sleep().

  1. BackgroundTestRunnerThread.sleep(sleepTime * 1000); in run() method:This can not be an issue as it will be always called in BackgroundTestRunnerThread thread not in main thread.
  2. pause(int milliseconds) method: I can not see your main thread code but chances are you are calling the pause method from main assuming it will sleep the BackgroundTestRunnerThread thread but because it might be getting called from main thread it will make main thread sleep not the other one.

Hope this helps.

Autres conseils

Thread.sleep() is a static method. The current thread sleeps. Whatever thread you supply is ignored. See the Javadoc.

sleep() is a static method in Thread and always sleeps the current thread, even if you attempt to call it on a thread object. This will also give you a compiler warning:

The static method sleep(long) from the type Thread should be accessed in a static way

Is there a way to send a message into the thread that is running BackgroundTestRunnerThread and have it sleep (i.e., have sleep called from within the other thread)?

The canonical way to communicate between threads would be to use a Handler and a Looper.

Also, for scheduling purposes, consider Handler postDelayed() instead of sleeping the thread.

Create a queue of tasks where you store which thread should sleep and with your threads which might need to sleep periodically check the first element of the queue. If it matches the thread, then pop the element of the queue and call the sleep method.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top