多視窗運作

在 Android 9 (和以下版本) 中,應用程式會在下列情況下進入 PAUSED 狀態:

  • 在應用程式仍可見 (因此未停止) 的情況下,在應用程式頂端啟動新的半透明活動。
  • 活動失去焦點,但未遭遮蔽,且使用者可以與其互動。舉例來說,在多視窗模式下,系統可同時顯示多個活動並接收觸控輸入內容。

這兩種情況的差異在於應用程式必須執行的「暫停」時間長短,但無法在應用程式層級做出區隔。

在 Android 10 中,可聚焦的活動會在可見堆疊中處於 RESUMED 狀態。對於使用 onPause() 而非 onStop() 來停止重新整理 UI 和與使用者互動的應用程式,這可提升與多視窗和 MD 模式的相容性。因此:

  • 分割畫面中的兩個活動都會恢復。
  • 系統會重新啟用任意形式視窗模式中所有顯示在頂端的活動。
  • 多個螢幕上的活動可同時重新啟動。

圖 1. 在摺疊式裝置上使用多視窗運作

圖 2. 在電腦模式下支援多視窗運作

如果活動無法聚焦或部分遮蔽,就會處於 PAUSED 狀態,例如:

  • 在已最小化的分割畫面 (側邊有啟動器) 中,頂端活動不會復原,因為無法聚焦。
  • 在子母畫面模式中,活動不會恢復,因為無法聚焦。
  • 當活動遭到相同堆疊中其他透明活動覆蓋時。

這種做法會向應用程式指出,活動只能在 RESUMED 狀態下接收使用者輸入內容。在 Android 10 之前,活動也可以在 PAUSED 狀態下接收輸入內容 (例如,在搭載 Android 9 的裝置上,嘗試同時觸碰分割畫面中的兩個活動)。

為保留先前 Android 版本的「resumed」信號 (並在應用程式應取得專屬存取權或單例資源存取權時進行通訊),Android 10 包含了新的回呼:

Activity#onTopResumedActivityChanged(boolean onTop)

在呼叫時,系統會在 Activity#onResume()Activity#onPause() 之間呼叫此回呼。這個回呼是選用功能,可略過,因此活動可以從 RESUMED 轉換為 PAUSED 狀態,而不必成為系統中最上層的活動。例如在多視窗模式下。由於此回呼為選用項目,因此並非 Activity 生命週期的一部分,因此不應經常使用。

上一個頂層復原活動會在下一個頂層復原活動接收 onTopResumedActivity(true) 之前,接收並完成 onTopResumedActivity(false) 的執行作業,除非上一個活動花費太多時間處理方法呼叫,並達到 500 毫秒的逾時限制。

相容性

如要在實作多視窗同時執行時維持相容性,請考慮採用下列解決方案。

在單一應用程式程序中重新啟用多個活動

  • 問題:在 Android 9 以下版本中,系統一次只會繼續執行一個活動。所有活動之間的轉換都會在暫停一個活動後再繼續另一個活動。有些應用程式和架構 (例如 Flutter 或 Android 的 LocalActivityManager) 會利用這項事實,並在單例中儲存有關已繼續執行活動的狀態。
  • 解決方法。在 Android 9 以下版本中,如果同一個程序中的兩個活動都重新啟動,系統只會重新啟動 Z 順序較高的活動。以 Android 10 為目標版本的應用程式可同時支援多個活動。

同時存取攝影機

  • 問題。這些問題也出現在 Android 9 以下版本。舉例來說,在子母畫面模式下,全螢幕和已重新啟用的活動可能會將相機焦點交給位於頂端的暫停活動,但如果廣泛採用多視窗和多螢幕模式,則會更容易曝光。
    • 由於 RESUME 狀態有所變更,應用程式可能會在恢復時與攝影機中斷連線。為解決這個問題,應用程式必須在不當機的情況下處理相機中斷連線。斷線時,應用程式會收到斷線回呼,且所有對 API 的呼叫都會開始擲回 CameraAccessException
    • resizeableActivity=false 無法確保該應用程式可取得專屬相機存取權,原因在於其他畫面可能開啟了使用相機的其他應用程式。
  • 解決方案。開發人員應加入應用程式與相機中斷連線時的邏輯。如果應用程式與攝影機中斷連線,應監控攝影機可用性回呼,嘗試重新連線並繼續使用攝影機。除了現有的 CameraManager#AvailabilityCallback#onCameraAvailable() 回呼之外,Android 10 也新增了 CameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged(),可處理焦點 (和相機優先順序) 在多個已暫停的活動之間切換的情況。應用程式開發人員應使用這兩種回呼,判斷何時適合嘗試存取相機。

多視窗運作

在 Android 10 中,活動生命週期狀態是由可見度和 Z 順序決定。如要確保活動的顯示設定更新後處於正確狀態,並評估適用的生命週期狀態,請從不同位置叫用 ActivityRecord#makeActiveIfNeeded() 方法。在 Android 10 中,active 代表 RESUMEDPAUSED,且只適用於這兩個例項。

在 Android 10 中,系統會在各個堆疊中個別追蹤活動的復原作業,而非在系統中的單一位置。這是因為在多視窗模式中,可以同時執行多個活動轉場。詳情請參閱 ActivityStack#mInResumeTopActivity

頂層暫停活動回呼

在可能導致頂層活動變更的動作 (例如活動啟動、重新啟動或 Z 順序變更) 之後,系統會叫用 ActivityStackSupervisor#updateTopResumedActivityIfNeeded()。這個方法會檢查最上層的重新啟用活動是否有變更,並視需要執行更新。如果先前的頂層繼續執行活動未釋出頂層繼續執行狀態,系統會傳送頂層繼續執行狀態遺失訊息,並在伺服器端排定逾時時間 (ActivityStackSupervisor#scheduleTopResumedStateLossTimeout())。在先前活動釋出狀態後,或在達到逾時時間時,系統會將頂層繼續執行狀態的報表傳送至下一個活動 (請參閱以下用法:

ActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()

我們新增了 TopResumedActivityChangeItem 交易項目,用於向用戶端回報頂層暫停狀態變更,並利用 Android 9 的 ActivityLifecycler 架構。

頂層暫停狀態會儲存在用戶端,每次活動切換至 RESUMEDPAUSED 時,也會檢查是否應叫用 onTopResumedActivityChanged() 回呼。這樣一來,您就能在伺服器和用戶端之間,將生命週期狀態和頂端暫停狀態的通訊進行特定分離。