首頁 > 軟體

橫豎屏切換導致頁面頻繁重啟screenLayout解析

2023-11-03 18:00:31

前言

前幾天多名使用者反饋同一個問題,在小新平板上無法上網課,點選上課按鈕後就退回到首頁了。同事瞭解了一下發現小新平板現在銷量特別好,於是趕緊申請了一臺測試機打算看看到底是什麼問題。

最後同事發現是screenLayout的問題,在manifest中為需要橫豎屏切換的Acitivty設定screenLayout即可,如下:

<activity android:name=".MainActivity"
  android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
    android:launchMode="singleTask">
    <intent-filter>
       ...
    </intent-filter>
</activity>

我們之前android:configChanges設定是orientation|keyboardHidden|screenSize,缺少了screenLayout。

但是為什麼在其他裝置上沒問題,唯獨在小新平板上有問題呢?而且為什麼新增了screenLayout就解決問題了,這其中的原理是什麼?我非常好奇,於是自己研究了一下。

android:configChanges

首先我們要知道android:configChanges這個設定的作用,這裡我們來看看官方的介紹:

列出 Activity 將自行處理的設定變更。在執行時發生設定變更時,預設情況下會關閉 Activity 並將其重啟,但使用該屬性宣告設定將阻止 Activity 重啟。相反,Activity 會保持執行狀態,並且系統會呼叫其 onConfigurationChanged() 方法。

當Activity的設定發生變更時(如橫豎屏切換),如果在android:configChanges中沒有新增該設定,那麼就會關閉並重啟Activity,這時候debug會發現重新執行了onCreate。但是當我們新增了該設定,如果該設定發生變更,則不會重啟Activity,會呼叫onConfigurationChanged()方法。

那麼orientation就是對應著橫豎屏切換,keyboardHidden則是軟鍵盤彈出,screenSize則是螢幕尺寸改變。這麼來看我們設定了orientation應該就可以了,但是官方在這裡有一個提示,如下:

官方建議在設定orientation的同時設定screenSizescreenLayoutscreenSize我麼可以理解,橫豎屏切換時寬高會交換,那麼screenLayout是指什麼呢?

screenLayout

前面我們知道存在設定時會執行onConfigurationChanged(),這個函數的引數是Configuration型別的,這個類裡儲存著Activity的設定,我們來看看對screenLayout這個屬性的描述:

/**
Bit mask of overall layout of the screen. Currently there are four fields:
The SCREENLAYOUT_SIZE_MASK bits define the overall size of the screen. 
They may be one of SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_NORMAL, 
SCREENLAYOUT_SIZE_LARGE, or SCREENLAYOUT_SIZE_XLARGE.
The SCREENLAYOUT_LONG_MASK defines whether the screen is wider/taller than normal. 
They may be one of SCREENLAYOUT_LONG_NO or SCREENLAYOUT_LONG_YES.
The SCREENLAYOUT_LAYOUTDIR_MASK defines whether the screen layout is either LTR or RTL. 
They may be one of SCREENLAYOUT_LAYOUTDIR_LTR or SCREENLAYOUT_LAYOUTDIR_RTL.
The SCREENLAYOUT_ROUND_MASK defines whether the screen has a rounded shape. 
They may be one of SCREENLAYOUT_ROUND_NO or SCREENLAYOUT_ROUND_YES.
See Supporting Multiple Screens for more information.
**/
public int screenLayout;

可以看到screenLayout其實是承載著四個設定的:

  • 螢幕大小等級:有SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_LARGESCREENLAYOUT_SIZE_XLARGE四種
  • 是否寬屏:螢幕是否比普通螢幕更寬或更高
  • 螢幕方向:螢幕是從左向右顯示,還是從有向左顯示
  • 是否是圓角屏:螢幕是否有圓角

通過將screenLayout於對應mask進行與運算就可以得到當前螢幕在該屬性的值,比如:

screenLayout & SCREENLAYOUT_SIZE_MASK

就可以得到螢幕大小等級,一定是SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_LARGESCREENLAYOUT_SIZE_XLARGE之一。

四個mask對應的二進位制分別是:

  • SCREENLAYOUT_SIZE_MASK: 0000 0000 1111
  • SCREENLAYOUT_LONG_MASK: 0000 0011 0000
  • SCREENLAYOUT_LAYOUTDIR_MASK:0000 1100 0000
  • SCREENLAYOUT_ROUND_MASK: 0011 0000 0000

比如在我的測試機上得到的screenLayout是268435810,轉成二進位制就是

0001 0000 0000 0000 0000 0001 0110 0010

通過與四個mask分別計算得到SCREENLAYOUT_SIZE_NORMAL、SCREENLAYOUT_LONG_NO、SCREENLAYOUT_LAYOUTDIR_LTR和SCREENLAYOUT_ROUND_NO

而且無論橫屏還是豎屏,我的測試機的screenLayout是不變的,所以即使在android:configChanges中沒用新增screenLayout,橫豎屏切換的時候也不會重啟Activity,因為其他兩個屬性orientationscreenSize都新增了。

小新平板

那麼為什麼小新平板上會有不同的現象,在android:configChanges中新增screenLayout完後我在onConfigurationChanged函數中debug獲取screenLayout值,發現橫屏和豎屏這個值是不同的,分別是268435812和268435796。

通過與mask運算獲取四個屬性後對比發現,橫豎屏切換後SCREENLAYOUT_LONG_NO變成了SCREENLAYOUT_LONG_YES,所以沒新增screenLayout的時候就會導致Activity重啟,新增後就可以了。

至於為什麼重啟Activity會導致回退到首頁,其實是使用者表述問題,現象是應用重啟了。為什麼應用會重啟,這是因為我們的應用架構是單Activity的,頁面由fragment承載。當從詳情頁開啟上課頁面時,會通過程式碼手動將豎屏切換到橫屏(同時為了返回詳情頁時換回豎屏,在詳情頁手動切換回豎屏)。這時候Activity重啟並以橫屏狀態恢復所有fragment,但是恢復詳情頁時候,又切換到豎屏,所以又重啟;然後以豎屏狀態恢復到上課頁面,又進行了切換,於是死迴圈,最後系統將應用重啟。

總結

一直以來對android:configChanges沒有深入瞭解,正好趁著這個機會了解了一番,大家以後一定要注意這裡,特別注意官方檔案的提示,很重要。

以上就是橫豎屏切換導致頁面頻繁重啟screenLayout解析的詳細內容,更多關於screenLayout頁面重啟的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com