使用自動調整刷新率來改善影格速率

在 Android 中啟動動畫時,螢幕通常會提升至最高更新率,確保提供流暢的體驗。對於進度列和音訊視覺化工具等小型動畫,不需要這麼高的更新率,反而會導致耗電量增加。

自 Android 15 起,啟用 ARR 功能的裝置可從兩方面減少高更新率的駐留時間:

  • 透過全新的平台畫面更新率管理最佳化功能,應用程式預設可以較低的畫面更新率算繪,並僅在必要時提升至高畫面更新率。
  • 螢幕刷新率會動態配合內容的算繪率,不會出現延遲。

大多數應用程式都應能從 ARR 受益,不需進行任何修改,但您也可以視需要覆寫預設影格速率行為。

本頁面說明下列事項:

  • 每個 View 的影格速率決定方式。
  • ARR 決定影格速率的一般政策。
  • 如何手動覆寫預設影格速率行為。

View 投票機制

在 Android 的 View 系統中,UI 階層中的每個 View 都可以表示偏好的影格速率。系統會收集並合併這些偏好設定,為每個影格決定最終影格速率。這是透過投票機制達成,每個 View 會根據自己的影格速率屬性 (可以是類別或特定速率) 投票。檢視區塊通常會在繪製或更新時投票。這些票數會合併,以決定最終影格速率,然後傳送至較低層級的圖層,做為算繪提示。

目前大多數 Views 預設為「一般」影格速率,通常設為 60 Hz。如要提高影格速率,可以使用特定 API 自訂偏好設定,系統通常會選取最高影格速率。如要進一步瞭解如何使用這些 API,請參閱「設定影格速率或類別」一節。如要瞭解有關影格速率的一般政策,請參閱「一般 ARR 政策」一節。

影格速率類別

View 類別中,有不同幀率類別可用於投票。各類別的說明如下:

只有在需要重新繪製時,View 才會投票。最終影格速率取決於最高票數。舉例來說,如果所有票數都投給「Normal」,則會選取「Normal」。如果同時出現「正常」和「高」票數,系統會選擇「高」。

畫面更新率

除了影格速率類別,View 也可以指定偏好的影格速率,例如 30、60 或 120 Hz。如果有多個影格速率投票,最終影格速率會依下列規則決定:

  • 互為倍數:如果投票的影格速率互為倍數,系統會選擇最高值。舉例來說,如果投票結果為 30 Hz 和 90 Hz,則最終幀率會選取 90 Hz。
  • 彼此不是倍數
    • 如果任何一項投票結果超過 60 Hz,就會計為「高」票。
    • 如果所有票數都是 60 Hz 以下,則視為「正常」票數。

此外,如果同時有影格速率值和影格速率類別,通常會以較高的值決定最終顯示速率。舉例來說,如果投票結果是 60 Hz 和「高」的組合,或是 120 Hz 和「正常」的組合,通常會將算繪率設為 120 Hz。

除了應用程式的投票結果,同一影格內的不同元件也可能會將其他提示傳送至較低層級的層。其中許多項目都可能來自系統 UI 元件,例如通知匣、狀態列、導覽列等。最終影格速率值會根據多個元件的投票結果決定。

設定影格速率或類別

在某些情況下,您可能會偏好 View 的特定畫面更新率。舉例來說,如果動畫顯示不流暢,您可以將 View 的偏好影格速率設為「高」,藉此提高影格速率。此外,如果影片有緩慢或靜態的動畫 (通常以 24 或 30 Hz 播放),您可能會希望動畫以低於「正常」的速率播放,以減少耗電量。

您可以使用 setRequestedFrameRate()getRequestedFrameRate() API,指定特定 View 的偏好影格速率或類別。

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 顯示,因為每個 View 都將「Normal」設為偏好的影格速率。不過,為確保動畫更流暢,影格速率有時會提高至「高」。

一般 ARR 政策如下:

  • 觸控加速:偵測到觸控事件 (MotionEvent.ACTION_DOWN) 時,系統會在放開觸控後的一段時間內,將螢幕更新率提升至「高」,以維持回應速度。
  • 滑動手勢:滑動手勢的處理方式不同,重新整理頻率會隨著滑動速度減緩而逐漸降低。詳情請參閱「捲動改善」一節。
  • 應用程式啟動和視窗轉場:在應用程式啟動、視窗初始化和視窗轉場期間,系統也會在一段時間內提高螢幕更新率,確保視覺體驗流暢。
  • 動畫:如果動畫涉及移動或大小變化,當 View 的位置或大小變更時,系統會自動提高重新整理率,以提升流暢度。
  • SurfaceViewTextureView:系統會遵守並套用為 TextureViewSurfaceView 明確設定的畫面更新率

啟用及停用觸控增強功能

您可以在 Window 層級啟用和/或停用觸控加速功能。根據預設,使用者觸碰螢幕並將手指移開時,算繪速率會暫時提高。setFrameRateBoostOnTouchEnabled()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()

捲動功能改善

動態最佳化影格率的主要用途之一,是提升捲動 (滑動) 體驗。許多應用程式都非常依賴使用者向上滑動來查看新內容。ARR 捲動強化功能會隨著甩動手勢減緩,動態調整重新整理頻率,逐步降低影格速率。這樣一來,就能在維持流暢捲動的同時,更有效率地算繪畫面。

這項改善功能特別適用於可捲動的 UI 元件,包括 ScrollViewListViewGridView,可能不適用於所有自訂實作項目。

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。如要正確設定速度,請手動計算內容速度 (每秒像素數),前提是無法從 ScrollerOverScroller 取得必要資訊。

請注意,如果對不可捲動的元件呼叫 setFrameContentVelocity()getFrameContentVelocity(),這些呼叫就不會產生任何作用,因為系統會根據目前的政策,在移動時自動觸發更高的影格速率。

速度資訊對於調整算繪率至關重要。舉例來說,請考慮輕拂手勢。一開始,甩動速度可能很快,因此需要較高的算繪速率,才能確保流暢度。隨著手勢進展,速度會降低,因此可降低算繪率。

啟用及停用 ARR

ARR 預設為啟用,可提升電源效率。雖然可以停用這項功能,但我們不建議這麼做,因為這樣應用程式會消耗更多電量。只有在遇到嚴重影響使用者體驗的問題時,才考慮停用這項功能。

如要啟用或停用 ARR,請在 Window 上使用 setFrameRatePowerSavingsBalanced() 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>

Compose 的 ARR

Compose 1.9 也支援自動調整刷新率。 在 View 系統中,您可以使用 setRequestedFrameRate() 方法,為 View 要求特定影格速率。在 Compose 中,您可以使用新的修飾符指定可組合項的影格速率。這個修飾符函式與 setRequestedFrameRate() 類似,可接受正影格速率值 (以 Hz 為單位) 或預先定義的影格速率類別 FrameRateCategory

API 的簽章如下:

在下列程式碼片段中,新的影格速率修飾符 (Modifier.requestedFrameRate(120f)) 會套用至 Text 可組合函式。這個修飾符會導致 Text 可組合函式在繪製或製作動畫時 (例如不透明度變化),要求偏好的影格速率為 120:

var targetAlpha by remember { mutableFloatStateOf(1f) }
val alpha by
    animateFloatAsState(
        targetValue = targetAlpha,
        animationSpec = tween(durationMillis = 1000)
    )

Button(
    onClick = { targetAlpha = if (targetAlpha == 1f) 0.2f else 1f },
    modifier =
        Modifier.background(LocalContentColor.current.copy(alpha = alpha))
) {
    Text(
        text = "Click",
        color = LocalContentColor.current.copy(alpha = alpha),
        modifier = Modifier.preferredFrameRate(120f)
     // You can also pass frame rate category such as FrameRateCategory.High  to increase the frame rate
    )
  }

接著,系統會收集並整合所有可組合項目的偏好影格速率,以決定每個影格的最終影格速率。詳情請參閱 SetFrameRateSampleSetFrameRateCategorySample