大まかに言うと、ここで私が意図していることは次のとおりです。
-- BackgroundManagerService 内の BroadcastReceiver が Android からブロードキャストを受信します (正常に動作します)。
-- BackgroundManagerService 内の BroadcastReceiver がインテントを startTestsRunnerThread() に送信します (正常に動作します)。
-- startTestsRunnerThread() は、BackgroundTestRunnerThread を作成して開始します (正常に動作しているようです)。
-- BackgroundTestRunnerThread のインスタンスであり、作成されたばかりのスレッドが 60 秒間スリープ状態になります (動作しません)。「BackgroundTestRunnerThread.sleep(milliseconds);」の場合、広範なログから が実行され、メインスレッド内で実行されています。
編集:回答から、sleep() は静的メソッドであり、現在のスレッドでのみ機能することがわかりました。BackgroundTestRunnerThread を実行しているスレッドにメッセージを送信してスリープ状態にする (つまり、他のスレッド内からスリープを呼び出す) 方法はありますか?
https://stackoverflow.com/a/3072338/1783829および他の投稿によると、おそらく ScheduledExecutorService でこれを行う必要があることを認識していますが、それはここでの私の質問ではありません。現時点で、私の質問は、sleep() が別のスレッドではなくメインスレッドで実行されている理由についてです。これにより ANR (Android Not Responding) が発生し、Android がアプリを強制終了します。
ここに私の完全なコードがあります:
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");
}
}
}