在 Android 中啟動動畫時,螢幕通常會提高至最高的螢幕刷新率,以確保流暢的使用體驗。對於進度列和音訊視覺化工具等小型動畫,這種高刷新率並非必要,反而會導致高耗電量。
自 Android 15 起,透過自動調整螢幕更新率 (ARR) 功能,啟用裝置可從兩方面降低高螢幕更新率停留時間:
- 透過新的平台影格速率管理最佳化功能,應用程式預設以較低的畫面更新率算繪,並只在必要時提升至高畫面更新率。
- 螢幕刷新率會動態配合內容算繪率,不會造成卡頓。
雖然大多數應用程式不必進行任何修改,即可享有 ARR 的好處,但您也可以視需要覆寫預設的幀率行為。
本頁面將說明以下內容:
- 如何判斷每個 View 的影格速率。
- 這項政策是 ARR 決定影格速率設定值的一般政策。
- 如何手動覆寫預設影格速率行為。
View 投票機制
在 Android 的 View 系統中,UI 階層中的每個 View 都可以表示其偏好的影格速率。系統會收集並合併這些偏好設定,以決定每個影格的最終影格速率。這項功能是透過投票機制達成,每個 View 會根據其影格速率屬性 (可為類別或特定速率) 投票。檢視畫面通常會在繪製或更新時投票。系統會將這些投票結果加總,以決定最終的幀率,然後將其傳送至較低層級的圖層,做為算繪的提示。
目前,大多數 View 預設為「Normal」影格速率,通常會設為 60 Hz。如要使用更高的影格速率,您可以使用特定 API 自訂偏好設定,系統通常會選取最高的影格速率。如要進一步瞭解如何使用這些 API,請參閱「設定影格速率或類別」一節。如要瞭解關於影格速率的一般政策,請參閱「一般 ARR 政策」一節。
影格速率類別
在 View
類別中,有不同的影格速率類別可用於投票。各類別的說明如下:
REQUESTED_FRAME_RATE_CATEGORY_DEFAULT
:這個值可設為返回預設行為,表示這個 View 沒有影格速率資料。REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE
:檢視畫面不會明確影響影格速率。也就是說,即使 View 處於活動狀態,架構在決定影格速率時也不會考量這項因素。REQUESTED_FRAME_RATE_CATEGORY_NORMAL
:表示適合動畫的平均影格數,這類動畫不需要更高的影格數,也不需要高流暢度。這通常為 60 Hz 或接近 60 Hz。REQUESTED_FRAME_RATE_CATEGORY_HIGH
:表示適合需要高影格速率的動畫的幀率,這可能會提高流暢度,但也可能會增加電力消耗。
View 只會在需要重新繪製時投票。最終的幀率會以最高票數決定。舉例來說,如果所有投票結果都是「正常」,系統就會選取「正常」。如果同時有「正常」和「高」的投票結果,系統會選擇「高」。
畫面更新率
除了影格速率類別之外,View 也可以指定偏好的影格速率,例如 30、60 或 120 Hz。如果投出多個影格速率票數,最終影格速率會根據下列規則決定:
- 相乘:如果投票選出的影格速率是相乘的倍數,系統會選擇最高的值。舉例來說,如果有兩個投票結果 (30 Hz 和 90 Hz),系統會選取 90 Hz 做為最終的幀率。
- 不重疊:
- 如果任何投票次數超過 60 次/秒,就會計為「高」票。
- 如果所有投票次數都為 60 Hz 以下,則視為「正常」投票。
此外,如果影格速率值和影格速率類別同時存在,通常會以較高的值決定最終的顯示速率。舉例來說,如果同時收到 60 Hz 投票和「高」投票,或是 120 Hz 投票和「正常」投票,則算繪速率通常會設為 120 Hz。
除了應用程式提供的投票外,同一個影格內的不同元件,也可能會向較低層級的圖層傳送其他提示。其中許多元素可來自系統 UI 元件,例如通知遮罩、狀態列、導覽列等。最終的幀率值會根據多個元件的投票結果決定。
設定影格速率或類別
在某些情況下,您可以為 View 設定偏好的畫面更新率。舉例來說,如果動畫看起來不流暢,您可以將 View 的偏好影格速率設為「High」,以便提高影格速率。此外,如果影片中出現速度緩慢或靜態的動畫 (通常以 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 位置或大小變更時,提升流暢度。
SurfaceView
和TextureView
:系統會根據TextureView
和SurfaceView
明確設定的畫面更新率,並據此套用。
啟用及停用觸控加速功能
您可以在 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()
改善捲動功能
動態最佳化影格速率的其中一個主要用途,是改善捲動 (fling) 體驗。許多應用程式都需要使用者向上滑動才能查看新內容。當甩動手勢減緩時,ARR 捲動強化功能會動態調整重新整理率,逐漸降低影格速率。這可提供更有效率的算繪,同時維持流暢的捲動效果。
這項改善項目專門適用於可捲動的 UI 元件,包括 ScrollView
、ListView
和 GridView
,且可能不適用於所有自訂實作。
RecyclerView
和 NestedScrollView
支援 ARR 捲動功能。如要在應用程式中啟用這項功能,請升級至 AndroidX.recyclerview
和 AndroidX.core
的最新版本。詳情請參閱下表。
媒體庫 |
版本 |
|
1.4.0 |
|
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()
如需更多範例,請參閱 RecyclerView
和 ScrollView
。如要正確設定速度,如果無法從 Scroller
或 OverScroller
取得必要資訊,請手動計算內容速度 (每秒像素)。
請注意,如果在非可捲動元件的 View 上呼叫 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>