多視窗運作

在 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() 回呼。這樣一來,您就能在伺服器端和用戶端之間,針對生命週期狀態和頂端暫停狀態的通訊進行特定解耦。