リフレッシュ レートの自動調整でフレームレートを最適化する

Android でアニメーションが開始されると、スムーズなエクスペリエンスを実現するために、ディスプレイの更新レートが最大に引き上げられることがあります。進行状況バーやオーディオ ビジュアライザーなどの小さなアニメーションでは、この高いリフレッシュ レートは不要であり、消費電力が増加します。

Android 15 以降、リフレッシュ レートの自動調整(ARR)機能により、有効にしたデバイスでは、次の 2 つの面で高リフレッシュ レートの保持時間を短縮できます。

  • 新しいプラットフォームのフレームレート管理の最適化により、アプリはデフォルトで低いフレームレートでレンダリングし、必要に応じてのみ高フレームレートにブーストできます。
  • ディスプレイのリフレッシュ レートは、ジャンクが発生することなく、コンテンツのレンダリング レートに動的に調整されます。

ほとんどのアプリでは、変更なしで ARR を利用できますが、必要に応じてデフォルトのフレームレート動作をオーバーライドすることもできます。

このページでは、次について説明します。

  • 各ビューのフレームレートの決定方法。
  • ARR がフレームレートを決定する方法に関する一般的なポリシー。
  • デフォルトのフレームレートの動作を手動でオーバーライドする方法。

ビューの投票メカニズム

Android のビューシステムでは、UI 階層内の各ビューが優先フレームレートを表現できます。これらの設定は収集され、組み合わせられて、各フレームの最終的なフレームレートが決定されます。これは、各ビューがフレームレート属性(カテゴリまたは特定のレート)に基づいて投票する投票メカニズムによって実現されます。ビューは通常、描画時または更新時に投票します。これらの投票は統合され、最終的なフレームレートが決定されます。このフレームレートは、レンダリングのヒントとして下位レイヤに送信されます。

現在、ほとんどのビューのデフォルトのフレームレートは「通常」で、多くの場合 60 Hz に設定されています。より高いフレームレートが必要な場合は、特定の API を使用して設定をカスタマイズできます。通常、システムは最も高いフレームレートを選択します。これらの API の使用方法の詳細については、フレームレートまたはカテゴリを設定するをご覧ください。フレームレートに関する一般的なポリシーについては、一般的な ARR ポリシーをご覧ください。

フレームレートのカテゴリ

View クラスには、投票で使用できるさまざまなフレームレート カテゴリがあります。各カテゴリの説明は次のとおりです。

  • REQUESTED_FRAME_RATE_CATEGORY_DEFAULT: この値を設定すると、デフォルトの動作に戻り、このビューにフレームレートのデータがないことを示します。
  • REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE: ビューはフレームレートに明示的に影響しません。つまり、ビューがアクティブであっても、フレームレートの決定時にフレームワークはビューを考慮しません。
  • REQUESTED_FRAME_RATE_CATEGORY_NORMAL: 高いフレームレートを必要としないアニメーションや、高いスムーズさが不要なアニメーションに適した中程度のフレームレートを示します。通常は 60 Hz またはそれに近い値です。
  • REQUESTED_FRAME_RATE_CATEGORY_HIGH: 高いフレームレートを必要とするアニメーションに適したフレームレートを示します。フレームレートを高くするとスムーズになりますが、消費電力も増加する可能性があります。

ビューは、再描画が必要な場合にのみ投票します。最終的なフレームレートは、最も多くの票を集めたフレームレートによって決まります。たとえば、すべての投票が「標準」の場合、「標準」が選択されます。「Normal」と「High」の両方の投票があった場合は、「High」が選択されます。

フレームレート

ビューでは、フレームレートのカテゴリに加えて、優先するフレームレート(30 Hz、60 Hz、120 Hz など)を指定することもできます。複数のフレームレートの投票が行われた場合は、次のルールに基づいて最終的なフレームレートが決定されます。

  • 互いの倍数: 投票されたフレームレートが互いの倍数である場合は、最も高い値が選択されます。たとえば、30 Hz と 90 Hz の 2 つの投票がある場合、最終的なフレームレートとして 90 Hz が選択されます。
  • 互いの倍数ではない:
    • いずれかの投票が 60 Hz を超える場合は、「高」の投票としてカウントされます。
    • すべての投票が 60 Hz 以下の場合、その投票は「通常」としてカウントされます。

また、フレームレートの値とフレームレートのカテゴリの両方が指定されている場合は、通常、値が大きい方が最終的なレンダリング レートになります。たとえば、60 Hz の投票と「高」の投票、または 120 Hz の投票と「標準」の投票が組み合わせられている場合、レンダリング レートは通常 120 Hz に設定されます。

アプリからの投票に加えて、同じフレーム内の異なるコンポーネントから下位レイヤに他のヒントが送信されることもあります。これらの多くは、通知シェード、ステータスバー、ナビゲーション バーなどのシステム UI コンポーネントに起因する可能性があります。最終的なフレームレート値は、複数のコンポーネントからの投票に基づいて決定されます。

フレームレートまたはカテゴリを設定する

特定の状況では、ビューに優先フレームレートを設定できます。たとえば、アニメーションがスムーズに表示されない場合は、ビューの優先フレームレートを「高」に設定してフレームレートを上げることができます。また、動画に低速または静止のアニメーションがある場合(通常は 24 Hz または 30 Hz で再生されます)、消費電力を抑えるためにアニメーションを「通常」よりも低いレートで実行することもできます。

setRequestedFrameRate() API と getRequestedFrameRate() API を使用して、特定のビューの優先フレームレートまたはカテゴリを指定できます。

Kotlin

// Set the preferred frame rate category to a View

// set the frame rate category to NORMAL
view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL
// set the frame rate category to HIGH
view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_HIGH
// reset the frame rate category
view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT

// Set the preferred frame rate to a View

// set the frame rate to 30
view.requestedFrameRate = 30f
// set the frame rate to 60
view.requestedFrameRate = 60f
// set the frame rate to 120
view.requestedFrameRate = 120f

Java

// Set the preferred frame rate category to a View

// set the frame rate category to NORMAL
view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL);
// set the frame rate category to HIGH
view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_HIGH);
// reset the frame rate category
view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);

// Set the preferred frame rate to a View

// set the frame rate to 30
view.setRequestedFrameRate(30);
// set the frame rate to 60
view.setRequestedFrameRate(60);
// set the frame rate to 120
view.setRequestedFrameRate(120);

使用例については、TextureView をご覧ください。

一般的な ARR ポリシー

前のセクションでは、各ビューの優先フレームレートが「通常」に設定されているため、ほとんどのアニメーションがデフォルトで 60 Hz で表示されることについて説明しました。ただし、アニメーションをスムーズにするためにフレームレートが「高」に引き上げられる例もあります。

一般的な ARR ポリシーは次のとおりです。

  • タップ ブースト: タップイベント(MotionEvent.ACTION_DOWN)が検出されると、タップが解除された後しばらくの間、更新レートが「高」にブーストされ、応答性が維持されます。
  • スワイプ操作: スワイプ操作は別の方法で処理されます。スワイプの速度が遅くなると、更新頻度は徐々に低下します。この動作の詳細については、スクロールの改善セクションをご覧ください。
  • アプリの起動とウィンドウの遷移: アプリの起動、ウィンドウの初期化、ウィンドウの遷移中は、スムーズな視覚体験を実現するために、更新レートが一時的に引き上げられます。
  • アニメーション: 移動やサイズ変更を含むアニメーションは、ビューの位置やサイズが変更されたときのスムーズさを高めるために、自動的に更新レートが引き上げられます。
  • SurfaceViewTextureView: TextureViewSurfaceView に明示的に設定されたフレームレートが考慮され、それに応じて適用されます。

タップブーストを有効または無効にする

タップ ブーストは、Window レベルで有効または無効にできます。デフォルトでは、ユーザーが画面をタップして指を離すと、レンダリング レートが一時的に増加します。setFrameRateBoostOnTouchEnabled() API と getFrameRateBoostOnTouchEnabled() API を使用すると、特定の Window がタップされたときにレンダリング レートの増加を防ぐことができます。

Kotlin

// disable touch boost on a Window
window.isFrameRateBoostOnTouchEnabled = false 
// enable touch boost on a Window
window.isFrameRateBoostOnTouchEnabled = true
// check if touch boost is enabled on a Window
val isTouchBoostEnabled = window.isFrameRateBoostOnTouchEnabled

Java

// disable touch boost on a Window
window.setFrameRateBoostOnTouchEnabled(false)
// enable touch boost on a Window
window.setFrameRateBoostOnTouchEnabled(true)
// check if touch boost is enabled on a Window
window.getFrameRateBoostOnTouchEnabled()

スクロールの改善

フレームレートを動的に最適化する主なユースケースの 1 つは、スクロール(フリング)エクスペリエンスを改善することです。多くのアプリでは、ユーザーが上にスワイプして新しいコンテンツを表示することを前提としています。ARR スクロールの改善により、スワイプ操作が遅くなると更新レートが動的に調整され、フレームレートが徐々に低下します。これにより、スムーズなスクロールを維持しながら、レンダリングの効率を高めることができます。

この改善は、ScrollViewListViewGridView などのスクロール可能な UI コンポーネントにのみ適用され、すべてのカスタム実装で利用できるとは限りません。

ARR スクロール機能は、RecyclerViewNestedScrollView で使用できます。アプリでこの機能を有効にするには、AndroidX.recyclerviewAndroidX.core の最新バージョンにアップグレードしてください。詳しくは、次の表をご覧ください。

ライブラリ

バージョン

AndroidX.recyclerview

1.4.0

AndroidX.core

1.15.0

ベロシティ情報を設定する

カスタムのスクロール可能なコンポーネントがあり、スクロール機能を利用する場合は、スムーズ スクロールまたはフリング中にフレームごとに setFrameContentVelocity() を呼び出します。例として、次のコード スニペットをご覧ください。

Kotlin

// set the velocity to a View (1000 pixels/Second)
view.frameContentVelocity = 1000f
// get the velocity of a View
val velocity = view.frameContentVelocity

Java

// set the velocity to a View
view.setFrameContentVelocity(velocity);

// get the velocity of a View
final float velocity = view.getFrameContentVelocity()

その他の例については、RecyclerViewScrollView をご覧ください。速度を正しく設定するには、必要な情報を Scroller または OverScroller から取得できない場合は、コンテンツの速度(ピクセル / 秒)を手動で計算します。

スクロール可能なコンポーネントではないビューで setFrameContentVelocity()getFrameContentVelocity() が呼び出されると、現在のポリシーに基づいて移動時にフレームレートが自動的に増加するため、効果はありません。

速度情報は、レンダリング レートを調整するうえで重要です。たとえば、スワイプ ジェスチャーについて考えてみましょう。最初はフリングの速度が高くなるため、スムーズに動作させるにはレンダリング レートを高くする必要があります。ジェスチャーが進むにつれて速度が低下するため、レンダリング レートを下げることができます。

ARR を有効または無効にする

ARR はデフォルトで有効になっており、電力効率を高めています。この機能は無効にできますが、アプリの消費電力が増加するため、おすすめしません。この機能を無効にすることは、ユーザー エクスペリエンスに重大な影響を与える問題が発生した場合にのみ検討してください。

ARR を有効または無効にするには、WindowsetFrameRatePowerSavingsBalanced() API を使用するか、styles.xml ファイルで isFrameRatePowerSavingsBalanced() API を使用します。

次のスニペットは、Window で ARR を有効または無効にする方法を示しています。

Kotlin

// disable ARR on a Window
window.isFrameRatePowerSavingsBalanced = false 
// enable ARR on a Window
window.isFrameRatePowerSavingsBalanced = true  
// check if ARR is enabled on a Window
val isAdaptiveRefreshRateEnabled = window.isFrameRatePowerSavingsBalanced

Java

// disable ARR on a Window
window.setFrameRatePowerSavingsBalanced(false)
// enable ARR on a Window
window.setFrameRatePowerSavingsBalanced(true)
// check if ARR is enabled on a Window
window.isFrameRatePowerSavingsBalanced()

styles.xml ファイルで ARR を無効にするには、res/values/styles.xml のスタイルに次のアイテムを追加します。

<style name="frameRatePowerSavingsBalancedDisabled">
    <item name="android:windowIsFrameRatePowerSavingsBalanced">false</item>
</style>