※このブログは、Joe Muoio のブログをToshimi Hatanakaが日本向けに翻訳し加筆修正したものです。
遅延読み込み(Lazy Loading)とは、はじめにユーザーに表示するのに必要なデータだけを読み込みつつ、このあと表示される可能性のあるデータを、ユーザーがUIを操作している間にバックグラウンドで読み込んでおくという方法です。
これは、ウェブサイトやモバイルアプリでよく使われる手法です。最新のAlexa Presentation Language(APL)バージョン1.3では、遅延読み込みリストのエクスペリエンスを作成することができます。Echo ShowからFacebook Portal(USのみ)まで、APLをサポートするすべてのAlexaマルチモーダルデバイスでは、遅延読み込みリストを作成する機能を含め、バージョン1.3の新機能をサポートしています。
遅延読み込みリストの機能は、データソースの変更(新しく追加されたデータソースタイプ dynamicListIndex)、新しいリクエストタイプ、およびより多くのダイナミックリストを作成するためのディレクティブを使用することでスキルに実装することができます。これらの新機能により、「無限に」スクロールしたり、デバイス上で動的にリスト項目の値を更新(項目の追加と削除を含む)するような、項目数の多いリストをスムーズに表示するエクスペリエンスをユーザーに提供することができます。
このブログ記事では、APL 1.3でのデータソースの変更点を解説し、遅延読み込みリストを作成するための新しいディレクティブの使い方を紹介します。コードを見るのが好きな方は、GitHub.comのAlexa cookcook APL example, skill-demo-lazy-load-lists をチェックしてみてください。このデモでは、カラーを選択するAlexaスキルで遅延読み込みリストの機能を使用しています。
遅延読み込みリストの作成に入る前に、APLデータソースの変更点について説明します。
APLでは、データソースによって、デバイス上のAPLドキュメントの一部にデータをバインドすることができます。古いバージョンのAPLでは、objectデータソースか、型付けされていないデータソースしかありませんでした。Objectデータソースは、ssmlToSpeechトランスフォーマーやtextToHintトランスフォーマーなどのトランスフォーマーで使用します。型付けされていないデータソースは、APLドキュメントにバインドしたいすべてのデータ用に使用され、payload という名前のパラメーターを通してAPLドキュメントへ渡されます。
以前のバージョンのAPLでは、レスポンスのAPLデータソースオブジェクト全体がこのpayloadパラメータにバインドされており、データをpayload.[YOUROBJECTKEYS_HERE] のような書式で参照していました。既に作成済みのAPLドキュメントは後方互換性のため、まだ機能しますが、APL 1.3以降では、データソースのトップレベル変数の名前をAPLドキュメントに渡すよう変更するのが良いでしょう。
例えば、以前のバージョンのAPLドキュメントでは以下のように記述していました。
{
"type": "APL",
"version": "1.2",
"mainTemplate": {
"parameters": [
"payload"
],
"item": {
"type": "Text",
"text": "${payload.displayText.helloText}"
}
}
}
データソース
{
"displayText": {
"helloText": "hello world!"
}
}
APL 1.3 では同じデータソースに対してAPLドキュメントは以下のように記述することができます。
{
"type": "APL",
"version": "1.3",
"mainTemplate": {
"parameters": [
"displayText"
],
"item": {
"type": "Text",
"text": "${displayText.helloText}"
}
}
}
APLのバージョン番号の変更以外に、2つの変更点があることに注目してください。1つ目は、mainTemplateのパラメータ名です。トップレベルのオブジェクトを参照し、これをAPLドキュメントに渡しています。2つ目は、その参照方法です。APLはデフォルトでデータソース全体をpayloadパラメータにバインドしなくなったので、その参照をすべて削除することができます。以前のAPLドキュメントは、APLのすべてのバージョンでまだ動作しますが、新しいデータソースのdynamicIndexListをpayloadパラメータと組み合わせて使用することはできません。
パラメータ名にpayloadを使用すると、ドキュメント内で参照するデータソース全体がpayloadパラメーターにバインドされ、新しく追加されたデータソース型で提供される新機能は無視されます。payload以外のパラメータ名を使用した場合、APLはAPL RenderDocumentディレクティブのdatasourcesセクションでそれらのパラメータを探します。今後、新しいAPLドキュメントを作成する場合は、名前付きのデータソースを使用してください。
APL 1.3では、新しいタイプのデータソースdynamicIndexListが追加されました。これにより、動的なデータソースと遅延読み込みリストを作成するために必要なツールが提供されます。
以下は、dynamicListIndex データソースの例です。
"datasources": {
"colorDynamicSource": {
"type": "dynamicIndexList",
"listId": "DYNAMIC_INDEX_LIST_ID",
"startIndex": 0,
"minimumInclusiveIndex": 0,
"maximumExclusiveIndex": 130,
"items": [
{
"index": 0,
"name": "Alice Blue",
"value": "#F0F8FF"
},
...,
{
"index": 9,
"name": "Brown",
"value": "#A52A2A"
}
]
}
}
この例では、colorDynamicSource という名前のdynamicIndexListデータソースを表していて、インデックス(index)が 0 から始まる 130 色のリストの最初の10色を定義しています。 これは、前方にスクロールするリストを作成し、minimumInclusiveIndex と maximumExclusiveIndex にバインドされます。もし、後方にスクロールするリストを作成したい場合は、開始インデックスよりも小さい値を設定します。例えば、インデックスにリストの真ん中あたりの数(80など)を設定し、同じバウンディングインデックスを使用すると、 前方にも後方にもスクロールするリストが作成されます。
一度バウンディングインデックスがデバイスから要求されると、デバイスはそれ以上のデータを要求しなくなり、ユーザはそれ以上スクロールすることはできなくなります。これらの各フィールドの詳細については、 dynamicIndexList の技術文書を参照してください。
遅延読み込みリストは dynamicIndexList データソースが必要です。さらに、遅延読み込みリストを作成するには、ページャーやシーケンスの dataプロパティに dynamicIndexList をバインドする必要があります(コンテナはdataプロパティを持ってはいますが、遅延読み込みリストはサポートされておらず、他の動的データ・ソース機能でサポートされています)。必要に応じて、Alexa 対応のマルチモーダルデバイスでは、loadIndexListDataRequest を使用して新しいデータのリクエストを送信します。
以下に例を示します。
{
"request": {
"type": "Alexa.Presentation.APL.LoadIndexListData",
"requestId": "amzn1.echo-api.request.1",
"timestamp": "2020-03-26T19:47:02Z",
"locale": "en-US",
"token": "YOUR_RENDER_DOCUMENT_TOKEN",
"correlationToken": "SYSTEM_GENERATED_TOKEN",
"listId": "DYNAMIC_INDEX_LIST_ID",
"startIndex": 20,
"count": 10
}
}
ここで、いくつか注意点があります。
{
"directives": [
{
"type": "Alexa.Presentation.APL.SendIndexListData",
"token": "YOUR_RENDER_DOCUMENT_TOKEN",
"correlationToken": "SYSTEM_GENERATED_TOKEN",
"listId": "DYNAMIC_INDEX_LIST_ID",
"startIndex": 20,
"minimumInclusiveIndex": 0,
"maximumExclusiveIndex": 130,
"items": [
{
"index": 70,
"name": "Lime Green",
"value": "#32CD32"
},
...,
{
"index": 78,
"name": "Medium Spring Green",
"value": "#00FA9A"
},
{
"index": 79,
"name": "Medium Turquoise",
"value": "#48D1CC"
}
]
}
]
}
startIndex の項目はリクエストの数と一致させ、デバイスがリクエストした数と同じ数のレスポンスを返す必要があります。
correlationToken はリクエストと一致している必要があります。minimumInclusiveIndex と maximumExclusiveIndex のインデックスは、以前のレスポンスで送信されている場合は不要です。この遅延読み込みリストのディレクティブと動的データソースの UpdateIndexListData ディレクティブの両方を組み合わせることで、複雑なマルチモーダルエクスペリエンスを作成することができます。
GithubのAlexa-cookbookにサンプルコードがあります。ここではそのデモを紹介します。
タッチスクロールで400色以上ある色のリストをブラウズし、タッチまたは音声で好みの色を選択します。すると、選択した色がリストの一番上に表示され、ヘッダーの色が選択した色に更新されます。また、ヘッダー部分で sequence か pager のどちらかをタッチして選択すると、APLドキュメントのメインコンポーネントが、シーケンスコンポーネントまたはページャーコンポーネントに切り替わります。 この時、一方のドキュメントから別のドキュメントに新しいRenderDocumentが送信されています。
このサンプルでは色の情報は colors.json というファイルから読み込んでいますが、外部のAPIサービスからデータを読み込むシナリオも考えられます。その場合、スキルが一度にすべてのデータをリクエストするよりも、遅延読み込みリストを利用するメリットが多くなります。特にページごとに分割してデータを取得できるAPIサービスが利用できる場合には便利です。 外部のAPIサービスを使用する場合、ある程度の待ち時間が発生します。データの一部を取得するのに一度だけ呼び出しを行い、あとはデバイスからそれ以降のデータを複数回に分けてAPIコールさせることで、待ち時間を短縮し、ユーザーエクスペリエンスを向上させることができます。
サンプルコードでは、新機能の APL エラーリクエストもデモしています。Node.js のコードの中に APLRuntimeErrorHandlerというハンドラーがあります。これは、Alexa Skills Kit (ASK) SDK を使用してリクエストハンドラを書くのと全く同じように書かれていて、何らかのエラーが発生した場合には、そのエラーログを残し空のレスポンスを返しています。状況によっては、エラーに基づいてここから行き先を修正するレスポンスを送信することも可能です。すべてのエラーケースのリストはこちらの技術文書に掲載されています。
GitHub.com の README.md にサンプルスキルをデプロイしてテストするための手順が記載されています。ご自身のAlexa開発者アカウントでサンプルスキルをデプロイし動作を確認してみてください。サンプルスキルを改造して、あなたならではのマルチモーダルスキルのプロトタイプを作ってみてはいかがでしょうか?