APLドキュメントのレイテンシーを短縮する

APLドキュメントのレイテンシーを短縮する

ユーザーは、スキルが遅延なくリクエストに応答することを期待しています。スキルに視覚コンポーネントが含まれている場合、コンテンツを表示する際のレイテンシーがユーザーエクスペリエンスを低下させる可能性があります。

Alexa Presentation Language(APL)ドキュメントのパフォーマンスを向上させ、ユーザーが認識する可能性のあるレイテンシーを低減させるには、以下のベストプラクティスを使用してください。

画像の代わりにAlexa Vector Graphics(AVG)を使用する

画像を使用すると、コンテンツの魅力を高めることができますが、同時にレイテンシーも増加する可能性があります。APLドキュメントで画像を表示する場合、デバイスは指定されたソースURLから画像を読み込む必要があります。

画像の代わりにベクターグラフィックを表示することで、レイテンシーを低減することができます。Alexa Vector Graphics(AVG)形式では、JSONコードでグラフィックを定義できます。定義したグラフィックは、VectorGraphicコンポーネントをドキュメントに配置して表示できます。

AVG形式の詳細については、Alexa Vector Graphics形式を参照してください。

VectorGraphicコンポーネントの詳細については、VectorGraphicを参照してください。

長いスクロールリストに動的データソースを使用する

長いスクロールリストを表示する場合は、動的データソースを使用して、データを小さなバッチでデバイスに送信します。ユーザーがリストをスクロールすると、Alexaがスキルに追加データをリクエストし、スキルは表示用の新しいデータを含む更新されたデータソースで応答します。

プログレッシブ読み込み(遅延読み込み)は、リストを表示する以下のレスポンシブ対応テンプレートで使用できます。

独自のドキュメントを作成する場合は、以下のコンポーネントでプログレッシブ読み込みを使用できます。

リストにプログレッシブ読み込みを使用するには

  1. リスト項目を含むデータソースを、dynamicIndexListデータソースとして定義します。詳細については、dynamicIndexListデータソースを参照してください。
  2. APLドキュメントで、リストを表示するコンポーネントにデータソースをバインドします。
    • レスポンシブ対応テンプレートを使用する場合は、データソースをlistItemsプロパティにバインドします。
    • Sequenceなどのプリミティブコンポーネントから独自のリストを作成する場合は、データソースをdataプロパティにバインドします。

    詳細については、動的なデータソースをAPLドキュメントにバインドするを参照してください。

  3. スキルコードで、ディレクティブを使用してユーザーのスクロールに応じてリストを管理します。詳細については、ディレクティブとリクエストを使用してリストを管理するを参照してください。

動的データソースの例については、APLの遅延読み込みリストのデモを参照してください。

URLベースのパッケージの読み込み数を制限する

APLパッケージを使用すると、リソースの共通レイアウトを別のファイルに定義して、importプロパティを使用してドキュメントに読み込むことができます。パッケージは、モジュール化された管理しやすいAPLドキュメントを作成するための重要な要素です。ただし、デバイスでドキュメントをレンダリングする前にURLまたはキャッシュからパッケージを取得する必要があるため、パッケージの読み込みにはコストがかかります。さらに、パッケージではほかのパッケージの読み込みを行うこともあるため、負荷が増大する可能性もあります。

パッケージを読み込む際のガイドラインは以下のとおりです。

  • 読み込むパッケージがすべて必要なものであることを確認してください。APLドキュメント内で参照していないパッケージは、すべて削除してください。
  • 接続を開いてパッケージをダウンロードする時間がかかるため、読み込みには複数の小さなパッケージよりも、1つの大きなパッケージの方が適しています。

検討すべき対応策としては、レスポンシブ対応コンポーネントとレイアウトのalexa-layoutsを読み込んでから、必要に応じて、独自のカスタムレイアウトを含む追加のカスタムパッケージを1つ読み込むという方法があります。

前のドキュメントに戻る場合はBackstackを使用する

Backstack Extensionを使用すると、ユーザーが以前表示したAPLドキュメントに移動することができます。Backstackを使用して前のドキュメントに戻る場合は、ドキュメントが既にインフレートされているため、デバイスでドキュメントをすばやくレンダリングできます。

Backstackを使用すれば、スキルにリクエストを送信して、スキルから前のドキュメントを含むRenderDocumentディレクティブが返されるのを待機する必要がなくなります。

Backstack Extensionの詳細については、APL Backstack Extensionを参照してください。

可能な限りレイアウトを使用する

レイアウトは、プリミティブコンポーネントとレイアウトで構成されたカスタムコンポーネントとして機能します。レイアウトを使用すると、よりモジュール化された管理しやすいドキュメントを作成できます。また、ドキュメントのレイアウトを再利用して、コードを簡素化することもできます。

レイアウトを使用することで、レイテンシーも短縮されます。デバイスでは、ドキュメントのインフレート時にレイアウトがキャッシュされます。したがって、デバイスでドキュメントを表示するにつれて、レイアウトの読み込み速度は速くなります。

カスタムレイアウトの作成の詳細については、APLレイアウトを参照してください。

スキルコードへのラウンドトリップではなくオンデバイスでの更新を行う

APLドキュメントでSendEventコマンドを使用すると、スキルにUserEventリクエストを送信できます。コードでは、このイベントを処理して応答を返します。応答には、読み上げる内容、更新されたAPLドキュメントを表示するRenderDocumentディレクティブ、既存のドキュメントを更新するコマンドを実行するExecuteCommandsディレクティブを含めることができます。

SendEventコマンドは、デバイス上で行われた更新についてスキルに通知し、Alexaの音声応答をトリガーする場合に便利です。ただし、デバイスとスキル間でこの「ラウンドトリップ」を使用すると、レイテンシーは長くなります。UserEventリクエストからRenderDocumentディレクティブを再送信して、更新されたAPLドキュメントをレンダリングするという処理も、時間とコストが多くかかります。

この代わりとして、APLコマンドを使用して視覚表示を直接更新すれば、スキルにリクエストを送り返して応答を待機する必要がなくなります。RenderDocumentディレクティブを使用してドキュメント全体を再送信することは、可能な限り避けてください。

こうすることで、視覚的な変更を行った後でSendEventコマンドを使用して、必要に応じてスキルに変更を通知することができます。ユーザーは、スキルへのラウンドトリップを待つことなく、視覚的な更新をすぐに確認できます。

たとえば、以下のコマンドの配列では、PressCountというバインドされたプロパティを更新し、アニメーションを実行してTextコンポーネントをフェードインさせてから、バインドされたプロパティの最新の値を含むUserEventをスキルに送信します。ユーザーから見ると、この画面はレイテンシーなしですぐに更新されます。

[
    {
        "type": "SetValue",
        "property": "PressCount",
        "value": "${PressCount + 1}"
    },
    {
        "when": "${PressCount == 1}",
        "type": "AnimateItem",
        "duration": 2000,
        "componentId": "buttonPressCount",
        "value": {
            "property": "opacity",
            "to": 1
        }
    },
    {
        "type": "SendEvent",
        "arguments": [
            {
                "buttonPressed": "pressCountButton",
                "pressCount": "${PressCount}"
            }
        ]
    }
]

以下は、APLドキュメント全体の例です。押した回数をカウントボタンを押すと、カウンターが増分され、ボタンを押した合計回数が画面に表示されます。カウントをリセットボタンを押すと、カウンターがゼロにリセットされ、ボタンを押した回数を示すテキストが非表示になります。どちらのボタンもSendEventを呼び出し、ほかのコマンドが終了した後で、現在のボタン押下のカウント数をスキルに通知します。

以下は、2つのボタンによって生成されたUserEventのリクエストハンドラーの例です。SendEventは視覚的な更新が行われた後に実行されるため、スキルへのラウンドトリップ中の遅延は認識されにくくなります。

クリップボードにコピーされました。

このサンプルコードは、Alexa Skills Kit SDK for Node.js(v2)を使用しています。

const ButtonPressEventHandler = {
    canHandle(handlerInput){
        // このハンドラーを両方のボタンに使用します。

        const requestEnvelope = handlerInput.requestEnvelope;

        return Alexa.getRequestType(requestEnvelope) === 'Alexa.Presentation.APL.UserEvent'
         && (requestEnvelope.request.source.id === 'pressCountButton'
         || requestEnvelope.request.source.id === 'resetButton');

    },
    handle(handlerInput){
        console.log("ButtonPressEventHandlerで、");

        // 引数からボタンデータを取得してログに記録します。実際の
        // スキルでは、これらの値を永続ストレージに保存したり、
        // 入力に固有の音声応答を作成したりすることができます。
        const buttonData = handlerInput.requestEnvelope.request.arguments[0];

        console.log("デバイスからボタンの押下に関するデータを取得しました。");
        console.log("報告されたボタンの押下回数:" + buttonData.buttonPressed);
        console.log("最新のボタン押下のカウント数:" + buttonData.pressCount);

        // リセットボタンの場合のみ音声応答を返します。
        if (buttonData.buttonPressed === 'resetButton'){
            return handlerInput
                .responseBuilder
                .speak("ボタンのカウント数をゼロにリセットしました。")
                .getResponse();
        }

    }
};

APLコマンドの動作の詳細については、APLコマンドを参照してください。使用可能なコマンドセットについては、以下を参照してください。

RenderDocumentディレクティブとUserEventリクエストの詳細については、Alexa.Presentation.APLインターフェースのリファレンスを参照してください。