前回、アクションについて解説するなかで同期と非同期の区別が登場しました。今回はその同期と非同期について、UIスレッドとワーカースレッドの二つを主軸に見ていきます。
同期と非同期
Pepperではタブレットと本体でそれぞれ異なるプロセスが動いており、二つのCPU間にはUSBを経由したTCP/IPによる通信があります。 同期と非同期のどちらでアクションを実行するかは、実際に動かしてみた上での選択をお勧めします。
#1.UIスレッド
Androidシステムからのコールバック(onCreateやOnClickListenerなど)はUIスレッド上で動作します。
@Override
protected void onCreate(Bundle savedInstanceState) {
}
@Override
protected void onResume() {
}
タブレットからPepperに指示を出した場合、Pepperとタブレット間での通信が発生します。しかしUIスレッド上でのネットワーク通信は出来ないため、NetworkOnMainThreadExceptionがスローされてしまいます。そのため、UIスレッドからPepperに指示を出す際は非同期を使用するようにしてください。
実践:同期と非同期
同期:UIスレッドで呼ぶことができない
// UIスレッド
Say say = SayBuilder.with(qiContext)
.withText("こんにちは")
.build(); // NetworkOnMainThreadExceptionがスローされる
// UIスレッド
goTo.run(); // NetworkOnMainThreadExceptionがスローされる
非同期:UIスレッドで呼ぶことができる
// UIスレッド
Future<say> sayBuilding = SayBuilder.with(qiContext)
.withText("こんにちは")
.buildAsync();
// UIスレッド
goTo.async().run();
#2.ワーカースレッド
続いて、ワーカースレッドについて見ていきましょう。Androidのワーカースレッドは独自で管理することも可能ですが、QiSDKのライブラリに任せることもできます。
QiSDKは複数の方法により、ワーカースレッドで処理を実行させることが可能です。
例① ロボットライフサイクル
@Override
public void onRobotFocusGained(QiContext qiContext) {
}
@Override
public void onRobotFocusLost() {
}
例② Futureチェーン
future.thenConsume(future -> {
});
例③ リスナー
qiContext.getHumanAwareness().addOnHumansAroundChangedListener(humans -> {
});
以上の例はすべて、UIスレッド上ではなくワーカースレッドで同期します。
##実践:非同期が有効なシーン
2-1.アクションをキャンセルしたい場合
非同期でアクションを実行する必要があります。
Future<void>goToFuture = goTo.async().run();
...
goToFuture.requestCancellation();
2-2.複数のアクションを同時に実行したい場合
複数のアクションを、非同期で連続して実行する必要があります。
Future<void>sayFuture = say.async().run();
Future<void>goToFuture = goTo.async().run();
2-3.その他の場合
上記の2-1、2-2に該当しない場合は、同期か非同期のいずれかでアクションを実行します。
say.run();
もしくは
Future<void> sayFuture = say.async().run();
補足
メインスレッドからPepperにアクションを実行させたい場合、非同期を使用してください。