スキップしてメイン コンテンツに移動

Pepper SDK入門(8) アクションの連結

同期と非同期について、今回は様々なクラスやメソッドと共に解説を行っていきます。

1.同期と非同期

アクションを順番に実行したい場合、同期で実行するようにコードを書く必要があります。
//animateアクションのビルド
Animate animate = ...;
//animateアクションを同期で実行
animate.run();
//listenアクションのビルド
Listen listen = ...;
//listenアクションを同期で実行
listen.run();
 
ここではAnimateListenを同期で順番に実行していますが、これらのアクションは非同期で実行することも可能です。
//animateアクションを非同期で実行
animate.async().run();
 
//listenアクションを非同期で実行
listen.async().run();
 
単純にこれらのアクションを非同期で実行してしまうと、アクションが連結していないため双方のアクションが同時に開始されます。一つ目のアクションが終了してから二つ目のアクション(ここではAnimateが終わった後のListen)を開始するよう非同期で実行したい場合には、複数のアクションを連結させる必要があります。

2.Futures

Futureクラスについて説明します。

Futureとは

Futureクラスは非同期の操作をラップするオブジェクトであり、主として次のような非同期の処理を行うために使用されます。
  • アクションやリソースといったオブジェクトの作成
  • アクション実行の取り扱い(結果の取得やアクションのキャンセル)
  • 複数のアクション実行やリソース作成の連結

Futureの状態

Futureの状態には成功、アクションのキャンセルもしくはエラーの3つがあり、成功した場合には値を返却することがあります。
Future<T>は戻り値の型にTを対応付けるジェネリッククラスであり、例えばFuture<String>インスタンスであればStringが返却されます。値を返却しないような場合にはFuture<Void>を使用します。 また、getメソッドを使用することで同期的な値の取得が可能です。
Future<String> stringFuture = ...;
String value = stringFuture.get();//処理が完了するのを待って値を取得(同期)
getメソッドをコールすると現在のスレッドはブロックされます。 ラップされた操作にエラーが生じた場合にはExecutionExceptionがスローされ、操作がキャンセルされた場合にはCancellationExceptionがスローされるため、Futureの終わりにtry-catchを実装しましょう。
Future<String> stringFuture = ...;
try {
    String value = stringFuture.get();
//Futureが値を返して終了
} catch (ExecutionException e) {
//Futureがエラーで終了
} catch (CancellationException e) {
//Futureがキャンセルされて終了
}

3.連結用のメソッド

Futureクラスは非同期の処理を連結できる複数のメソッドを持っており、前半部分のthen、andThen、後半部分のConsume、Apply、Composeの組み合わせからなります。
  • thenConsume
  • thenApply
  • thenCompose
  • andThenConsume
  • andThenApply
  • andThenCompose

3-1.then / andThen

前半部分のthenとandThenの違いについて説明します。

then…

thenから始まるメソッドは一つ前の処理の結果に関係なく続きの処理を実行したいような連結に向いています。一つ前の処理をラップしたFutureへアクセス可能で、Fututeの状態を取得するにはisSuccess、hasError、isCancelledメソッドを使用してください。
Future<string>future = ...;
future.thenConsume(stringFuture -> {
    if (stringFuture.isSuccess()) {
//成功した場合の処理
//stringfuture.get()で値へアクセス
    } else if (stringFuture.isCancelled()) {
//キャンセルされた場合の処理
    } else {
//エラーになった場合の処理
//stribgFuture.getError()でエラーへアクセス
    }
});

andThen...

andThenから始まるメソッドでは一つ前の処理が成功した場合にのみ続きの処理を連結することが出来、複数の処理が一つ前の処理に依存している場合の使用に向いています。最初の処理をラップしたFutureの値へ直接のアクセスが可能です。
Future<string>future = ...;
future.andThenConsume(string -> {
});

連結用のメソッドの戻り値

then...、andThen...の戻り値は連続した2つの処理をラップしたFutureです。

thenから始まるメソッドの使用例

then..を使ってPepperに複数のモーションを非同期で順番に実行させたい場合は、以下のソースコードを参照してください。

//animateアクションのビルド
Animate firstAnimate = ...;
//animateアクションを非同期で実行
Future<void> firstDance = firstAnimate.async().run();

//複数のアニメーションを連結
Future<void>ballet = firstDance.thenCompose(dance -> {
    //animateアクションのビルド
    Animate secondAnimate = ...;
    //animateアクションを非同期で実行
    Future<void> secondDance = secondAnimate.async().run();
    return secondDance;
});

andThenから始まるメソッドの使用例

andThen...を使ってPepperに複数の異なるモーションを非同期で順番に実行させたい場合は、以下のソースコードを参照してください。

//animateアクションのビルド
Animate animate = ...;
//animateアクションを非同期で実行
Future<void> imitation = animate.async().run();

//アニメーションとlistenアクションを連結
Future<listenresult> guess = imitation.andThenCompose(animateFuture -> {
    //listenアクションをビルド
    Listen listen = ...;
    //listenアクションを非同期で実行
   Future<listenresult> answerListening = listen.async().run();
    return answerListening;
});

3-2.consume / apply / compose

次のメソッドの使用は2つ目の操作の戻り値に依存します。
  • ...Consume,
  • ...Apply,
  • ...Compose.

consume:

非同期で実行する処理に戻り値がない場合にはConsumeで終わるメソッドを使用します。
Future<string>future = ...;
Future<void> returnedOperation = future.andThenConsume(string -> Log.i(TAG, "Success: " + string));

apply:

非同期で実行する処理に戻り値がある場合にはApplyで終わるメソッドを使用します。
Future<string> future = ...;
Future<integer> returnedOperation = future.andThenApply(string -> string.length());

compose:

非同期で実行する処理がFutureを返す場合はComposeで終わるメソッドを使用してください。アクションの連結ではこのメソッドがメインになります。
Say say = ...;
Future<void> sayFuture = say.async().run();
Future<void> returnedOperation = sayFuture.andThenCompose(ignore -> {
    Animate animate = ...;
    Future<void>animateFuture = animate.async().run();
    return animateFuture;
});

4.コールバック

連結用のメソッドはそれぞれに、パラメータとして異なるコールバックインターフェースを用います。
オペレータ andThen... then...
...Consume Consumer Consumer<Future<T>>
...Apply Function Function<Future<T>,R>
...Compose Function<T,Future<R>> Function<Future<T>,Future<R>>

4-1.Consumer

ConsumerインターフェースにはFutureの結果の獲得に使用されるconsumeメソッドがあり、これはワーカースレッドで実行されます。使用例は以下のとおりです。

andThenConsumeを使ってFutureの結果のログ出力

//Java8
Future<string>future = ...;
future.andThenConsume(string -> Log.i(TAG, "Success: " + string));
//Java7
Future<string>future = ...;
future.andThenConsume(new Consumer<string>() {
    @Override
    public void consume(String string) throws Throwable {
        Log.i(TAG, "Success: " + string);
    }
});

4-2.Function

Functionインターフェースには新規の戻り値もしくはFutureを返すexecuteメソッドがあり、ワーカースレッドで実行されます。使用例は以下のとおりです。

andThenApplyを使ってFutureの結果を変換

//Java8
Future<string> future = ...;
future.andThenApply(string -> string.length());
//Java7
Future<string> future = ...;
future.andThenApply(new Function<String, Integer>() {
    @Override
    public Integer execute(String string) throws Throwable {
        return string.length();
    }
});

andThenComposeを使ってアクションの連結

//Java8
Animate animate = ...;
animate.async().run().andThenCompose(ignore -> {
    Say say = ...;
    return say.async().run();
});
//Java7
Animate animate = ...;
animate.async().run().andThenCompose(new Function<Void, Future<Void>
>() {
    @Override
    public Future<Void> execute(Void ignore) throws Throwable {
        Say say = ...;
        return say.async().run();
    }
});

コメント

このブログの人気の投稿

Pepper SDK入門(1) Pepper SDKプラグインのインストール

Pepper SDK for Androidのサイトが黙々とアップデートされています。そろそろ感もありますので、Pepper SDK for Androidの公式サイトを読みつつ、理解したことをまとめていきたいと思います。 Android Studio対応版Pepperでは、AndroidのActivityからAPIを使用して、会話や動きを制御することが出来るようです。Pepper SDK for AndroidはAndroid Studioのプラグインであり、グラフィカルツール、Javaライブラリ、QiSDKを提供します。 Android Studio対応版Pepper向けのロボアプリを開発するため、以下に従って開発環境を整えましょう。 《OSバージョンの確認》 まずは、OSとバージョンの互換性を確認してください。 Linux … Ubuntu 16.04 Xenial Xerus - 64bits only Windows … Microsoft Windows 10 - 64bits only Mac … Mac OS X 10.12 Sierra 《Android Studioのインストール》 ロボアプリはPepperにビルトインされたAndroidのタブレット上で動くアプリであり、それによって開発を行うため、Android Studioのインストールが必要です。 <必要なもの> ・Android Studio Version 2.3かそれ以降 最新の安定したバージョンのインストールを推奨しています。 ・Java Development Kit (JDK) Android Studioの動作環境 Android Studioのインストールにあたっては、以下の公式インストールガイドに従ってください: http://developer.android.com/sdk/index.html 《Android SDKとビルドツールの入手》 Androidのアプリを開発するために、Android SDKとビルドツールのインストールが必要です。 <手順> ① Android Studioのツールバーから、 SDK Managerをクリックすると、SDK Managerが表示さ

Pepper SDK入門(3) はじめてのロボアプリ開発②

Androidプロジェクトの作成及びロボアプリの初期設定を行った前回に引き続き、Pepperのエミュレータと実機でアプリを実行するために必要な手順を確認していきます。 1.Pepperのエミュレータ  まずは、Pepperのエミュレータで動作確認するための方法についてです。 <手順> エミュレータボタン をクリックしてください。すると、ロボットエミュレータが表示されます。 プロジェクトにおける実行の構成でappが選択されているか を確認し、 選択されていない場合はそれを選択してください。 実行ボタン をクリックしてください。すると、Select Deployment Targetダイアログが表示されます。 ダイアログからPepperのエミュレータを選択してください。アプリがエミュレータにインストールされ、Robot Viewer上のバーチャルロボットで動作確認することが出来ます。 2.Pepperの実機  次に、Pepperの実機で動作確認するための方法を見ていきます。 <手順> Pepperのタブレットの設定を確認します。タブレットのホームにある設定アイコンをタップし、以下の設定を確認してください。 開発者モードが有効になっていること 開発者向けオプション、デバッグ、ADBも有効になっていること Android studioで、接続ボタン をクリックし、Robots Browserを表示してください。 Use fix portとUse fixed IP/hostnameにチェックを入れ、接続先のPepperのIPアドレスを入力してください。PepperのIPアドレスはタブレットの通知バーか、胸部ボタンを一回押すことで確認できます。 Selectボタンをクリックしてください。すると、セキュリティの警告が表示されます。 Pepperのパスワードを入力してください。初期パスワードはnaoです。変更している場合は管理者に確認して下さい。パスワード入力後にOKボタンをクリックすると、Robot Viewerが表示されます。 Pepperの実機に接続すると、同時にタブレットにもADB経由で接続されます。 プロジェクトにおける実行の構成でappが選択されてい

Pepper SDK入門(5) Robot focus と Robot lifecycle

Pepper SDK Plugin導入から始まり、簡単なロボアプリの開発を行ってきました。今回は、QiSDKの基本となるRobot focus と Robot lifecycleについて説明します。 1.フォーカスを理解する まずはロボットフォーカスについての簡単な説明です。 Activityがロボットのアクションを実行するためには、ロボットフォーカスが必要です。ロボットフォーカスはフォアグラウンドのActivityだけが保持することができ、ロボットフォーカスオーナーと呼ばれます。ロボットフォーカスはQiSDKに管理されており、Activityはいつでもロボットフォーカスを獲得したり喪失したりする可能性があります。  2.ロボットライフサイクル Pepper SDK入門(2) はじめてのロボアプリ開発①で登場したロボットライフサイクルについてです。 QiSDKがそれぞれのActivity用のロボットフォーカスを渡すために、RobotLifecycleCallbacksインタフェースを実装したオブジェクトが必要になります。以下はActivityにRobotLifecycleCallbacksインタフェースを実装した例です。 public class MyActivity extends RobotActivity implements RobotLifecycleCallbacks また、RobotLifecycleCallbacksオブジェクトにコールバックさせるにはonCreateメソッドでActivityとRobotLifecycleCallbacksオブジェクトをQiSDKに登録する必要があります。 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); QiSDK.register(this, this); } その上で、onDestroyメソッドでの登録解除も必要です。  @Override protected void onDestroy() { QiSDK.unregister(this, this); super.onDestroy(