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