0

大まかに言うと、ここで私が意図していることは次のとおりです。

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

ここに画像の説明を入力

4

4 に答える 4

2

私が見ることができるように、Thread.sleep は静的メソッドであり、現在実行中のスレッドのみをスリープさせ、sleep() を使用している場所が 2 つあります。

  1. BackgroundTestRunnerThread.sleep(sleepTime * 1000); run() メソッド内: これは、メイン スレッドではなく BackgroundTestRunnerThread スレッドで常に呼び出されるため、問題になることはありません。
  2. pause(int milliseconds) メソッド: メイン スレッド コードが表示されませんが、BackgroundTestRunnerThread スレッドをスリープ状態にすることを想定して main から pause メソッドを呼び出している可能性がありますが、メイン スレッドから呼び出される可能性があるため、メイン スレッドがスリープ状態にならない可能性があります別のもの。

お役に立てれば。

于 2014-04-01T12:33:10.773 に答える
1

sleep()の静的メソッドでThreadあり、スレッド オブジェクトで呼び出しようとしても、現在のスレッドを常にスリープ状態にします。これにより、コンパイラの警告も表示されます。

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

BackgroundTestRunnerThread を実行しているスレッドにメッセージを送信してスリープ状態にする方法はありますか (つまり、他のスレッド内からスリープを呼び出す方法はありますか)。

スレッド間で通信する標準的な方法は、 aHandlerと aを使用することLooperです。

また、スケジューリングの目的でHandler postDelayed()、スレッドをスリープ状態にする代わりに検討してください。

于 2014-04-01T10:15:27.320 に答える
1

Thread.sleep()静的メソッドです。現在のスレッドはスリープします。指定したスレッドは無視されます。Javadoc を参照してください。

于 2014-04-01T10:15:36.560 に答える
-1

スリープするスレッドを格納するタスクのキューを作成し、定期的にスリープする必要があるスレッドを使用して、キューの最初の要素をチェックします。スレッドと一致する場合は、キューの要素をポップして sleep メソッドを呼び出します。

于 2014-04-01T11:27:21.223 に答える