Save the date! Android Dev Summit is coming to Sunnyvale, CA on Oct 23-24, 2019.

何十億人ものユーザーに受け入れられるネットワーク接続

世界の半数以上のユーザーはアプリを 2G 接続で利用します。そのようなユーザーのエクスペリエンスを改善するには、データを保存し、リクエストをキューに格納し、画像処理のパフォーマンスを向上させることにより、低速接続とオフライン作業向けに最適化する必要があります。

これを実現するためにヒントをいくつかご紹介します。

画像を最適化する

画像をダウンロードしやすくする方法がいくつかあります。WebP 画像を提供する、画像のサイズを動的に変える、画像読み込みライブラリを使用するなどの方法です。

WebP 画像を提供する

  • ネットワーク経由で WebP ファイルを提供すると、画像の読み込み時間を短縮してネットワーク帯域幅を節約できます。WebP ファイルは同じ内容の PNG ファイルや JPG ファイルよりサイズが小さいことが多く、画像の品質は同等以上です。不可逆圧縮の設定でも WebP は元の画像とほぼ同等の画像を生成できます。Android では、不可逆圧縮の WebP サポートは Android 4.0(API レベル 14: Ice Cream Sandwich)以降、可逆圧縮 / 透過モードの WebP は Android 4.2(API レベル 17: Jelly Bean)以降で提供されています。

画像のサイズを動的に変える

  • アプリは端末の仕様に基づいて対象のレンダリング サイズの画像をリクエストし、サーバーはそれに適合するサイズの画像を提供するようにします。このようにすれば、ネットワークで送信されるデータを最小化し、各画像の保存に要するメモリ量を削減でき、パフォーマンスとユーザーの満足度を向上することができます。
  • ユーザーが画像のダウンロードを待機しなければならなくなると、ユーザー エクスペリエンスが損なわれます。適切な画像サイズを使用すれば、このような問題を解決できます。ネットワークの種類や品質に応じた画像サイズのリクエストを生成することをおすすめします。このサイズは対象のレンダリング サイズより小さくなる場合があります。
  • 事前に計算されたパレット値や低解像度のサムネイルなどの動的なプレースホルダを使用すると、画像を取得する際のユーザー エクスペリエンスを改善できます。

画像読み込みライブラリを使用する

  • アプリが同じ画像を 2 回以上取得することは避けてください。GlidePicasso といった画像読み込みライブラリは、画像を取得し、キャッシュして、ビューのフックを提供し、実際の画像の準備ができるまでプレースホルダ画像を表示できるようにします。画像はキャッシュに保存されるため、次回画像をリクエストするとこれらのライブラリからローカルコピーが返されます。
  • 画像読み込みライブラリがこのキャッシュを管理して最新の画像を保持するので、アプリのストレージが無制限に増大することはありません。

ネットワークを最適化する

最適なネットワーク エクスペリエンスを提供すると、ユーザー エクスペリエンスが向上します。たとえば、アプリをオフラインで使用可能にしたり、GcmNetworkManager とコンテンツ プロバイダを使用したり、ネットワーク リクエストの重複を排除したりします。

アプリをオフラインで使用可能にする

  • 農村部や発展途上地域では、しばしば端末のネットワーク接続が失われます。オフライン状態でも便利に使えるようにすれば、ユーザーはいつでもアプリを操作できます。そのためには、データをローカルに保存し、データをキャッシュに入れ、発信リクエストはキューに入れネットワーク接続が復旧したときに実行するようにします。
  • 接続が失われても、アプリではできるだけユーザーには通知しないでください。ユーザーに通知する必要があるのは、ネットワーク接続が不可欠である操作をユーザーが実行する場合のみです。
  • 端末の接続が失われた場合は、接続が復旧したときにネットワーク リクエストを(ユーザーに代わって)アプリが一括で実行する必要があります。たとえば、メール クライアントは端末がオフラインでも、メールの作成、送信、既存のメールの参照、移動、削除ができます。これらの操作はキャッシュに保存して、接続が復旧したときに実行することができます。これにより、端末の接続状況にかかわらずアプリは同じユーザー エクスペリエンスを提供できます。

GcmNetworkManager とコンテンツ プロバイダの使用

  • アプリでデータベースまたは同様の構造を使用してすべてのデータをディスクに保存すると、ネットワークの状況にかかわらず最適な動作を実現できます(たとえば SQLite と ContentProvider を使用する)。GCM Network ManagerGcmNetworkManager)はサーバーとデータを同期するための堅牢なメカニズムを提供します。一方、コンテンツ プロバイダContentProvider)はデータをキャッシュします。これらを組み合わせると、オフライン状態でも便利に動作可能なアーキテクチャが実現します。
  • アプリは、ネットワークから取得したコンテンツをキャッシュし、それ以降のリクエストを実行する前に、ローカルでキャッシュしたデータを表示する必要があります。この処理によって、端末がオフラインの場合や、低速または信頼性が低いネットワークに接続している場合でも、アプリを機能させることができます。

ネットワーク リクエストの重複排除

  • オフラインファーストのアーキテクチャでは、まずローカル ストレージからデータを取得しようとします。これに失敗すると、ネットワークからのデータの取得をリクエストします。ネットワークから取得したデータは、それ以降の取得のためにローカルにキャッシュします。この仕組みによって、同じデータに対するネットワーク リクエストは 1 回だけ実行され、それ以降のリクエストはローカルで処理されるようになります。その場合、長期間にわたって使用するデータにはローカルのデータベースを使用します(通常、android.database.sqlite または SharedPreferences)。
  • このアーキテクチャを使用すると、オフライン状態とオンライン状態の間のアプリのフローの簡素化も行われます。一方でネットワークから取得してキャッシュに入れ、他方でキャッシュから取得してユーザーに提示するという流れです。
  • 一時的に使用するデータには、DiskLruCache など、上限のあるディスク キャッシュを使用します。通常は変更されないデータは、ネットワーク経由で 1 回だけリクエストし、それ以降使用できるようにキャッシュしておかなければなりません。ニュース記事やソーシャルの投稿など、画像や一時的ではないドキュメントがこれに該当します。

データ転送を微調整する

アプリをネットワークの状態に適応させてユーザー エクスペリエンスを向上する方法はいくつかあります。たとえば、ネットワーク リクエストに優先順位をつけてユーザーが情報を待機する時間を短縮できます。また、ネットワーク速度の低下やネットワーク接続で発生する可能性のある変化を検出し、それに適応することもできます。

帯域幅の優先順位をつける

  • 端末の接続先ネットワークが長時間使用可能で信頼性が高いことを想定してはいけません。このため、アプリはネットワーク リクエストの優先順位を設定し、なるべく速やかに最も有用な情報をユーザーに表示する必要があります。
  • 必ずしも必要ではない情報を取得するために待たせるより、表示可能で関連性の高い情報をすぐに見せるほうがユーザー エクスペリエンスは向上します。また、ユーザーの待ち時間が短縮され、低速のネットワークでもアプリの利便性が高まります。
  • そのためには、リッチ メディアよりも先にテキストを取得するようにネットワーク リクエストのシーケンスを設定します。テキスト リクエストのほうがサイズが小さく、圧縮率が高く、高速に転送できる傾向があるため、アプリが有用なコンテンツを迅速に表示できます。ネットワーク リクエストの管理については、ネットワークの使用の管理に関する Android トレーニングで詳細をご確認ください。

低速の接続では帯域幅を節約する

  • アプリが速やかにデータを転送できるかどうかは、ネットワーク接続に依存します。ネットワークの品質を検出してアプリ側でネットワークの使用方法を調整すれば、最適なユーザー エクスペリエンスを実現できます。
  • 次のメソッドで、基本的なネットワークの品質を検出できます。これらのメソッドで取得したデータを使用して、アプリ側でネットワークの使用方法を調整し、ユーザーの操作に対して迅速に応答し続ける必要があります。
  • 低速の接続では、低解像度のメディアのみダウンロードするか、メディアを一切ダウンロードしないことを検討してください。そうすれば、低速の接続でもアプリを使うことができます。画像が存在しない、または読み込み中の場合は、常にプレースホルダを表示するようにします。Palette ライブラリを使用して、対象の画像と一致するプレースホルダのカラーを生成することで、動的なプレースホルダを作成できます。
  • Android 7.0(API レベル 24)以降の端末では、ユーザーがデータセーバー設定を有効にしてデータ使用を最小限に抑えることができます。Android 7.0 では、ConnectivityManager が拡張され、データセーバー設定を検出するようになっています。この機能の詳細については、データセーバーをご覧ください。

ネットワークの変化を検出してアプリの動作を変更する

  • ネットワークの品質は一定ではありません。場所、ネットワークトラフィック、その場所の人口密度に応じて変わります。よってアプリでネットワークの変化を検出し、それに応じて帯域幅を調整しなければなりません。そうすることで、ネットワークの品質に合わせてアプリのユーザー エクスペリエンスを調整できます。ネットワークの状態を検出するには、次のメソッドを使用します。
  • ネットワークの品質が低下したら、リクエストの数とサイズを削減します。ネットワークの品質が向上したら、最適なレベルにまでリクエストを増大させます。
  • 高品質の定額ネットワークでは、データをプリフェッチしてあらかじめ利用できるようにすることを検討してください。ユーザー エクスペリエンスの観点で説明すると、ニュース リーダー アプリの場合、2G 接続では一度に 3 件の記事を取得し、Wi-Fi では一度に 20 件の記事を取得するような対応が考えられます。ネットワークの変化に基づくアプリの動作の調整については、接続ステータスの監視に関する Android トレーニングで詳細をご覧ください。
  • ネットワーク接続に変化があると、CONNECTIVITY_CHANGE ブロードキャストが送信されます。アプリがフォアグラウンドのときは registerReceiver を呼び出して、このブロードキャストを受信できます。このブロードキャストを受信したら現在のネットワークの状態を再評価して、UI とネットワークの使用を適切に調整する必要があります。この機能は Android 7.0(API レベル 24)以降では使用できないので、マニフェストでこのレシーバを宣言しないでください。この点を含む Android 7.0 の変更点の詳細は、Android 7.0 の変更点をご覧ください。