前言
最近在升級targetsdkversion,我負責了一部分的升級適配工作,後面會找時間對Android升級targetsdkversion的相關工作做一個比較深入的總結。但是今天我想把一個問題單獨拎出來說一說。那就是網上盛傳的 Android8.0 "Only fullscreen opaque activities can request orientation "問題。這個問題從被大家發現,到現在已經快一年半了,解決方案都很全,之所以叫在分析,是因為這裡面還有些問題一直沒有被解釋清楚,昨天在做這個適配的時候也有些困擾,因此在這裡做一個簡短而全面的分析。
問題原由
我們先來說說這個問題的由來,最先在網上有人爆出,如果開發者把targetsdkversion調成27及以上,而且專案中的Activity主題設為透明,而又指定了activity螢幕的方向的話,在Android8.0的手機上會直接丟擲RunRuntimeException異常,並且列印的錯誤資訊裡面會有這段話:"Only fullscreen opaque activities can request orientation "
接著就有人指出這個是Android開發人員在開發Android8.0的時候的一次提交的程式碼造成的問題。點選傳送門
從上述提交中,我們能夠看到開發人員意在阻止非全屏的activity影響螢幕的方向。而根據程式碼追蹤到的程式碼片段大概是這裡:
if (ActivityInfo.isFixedOrientation(requestedOrientation) // 是否鎖定了螢幕方向
&& !fullscreen // 不是全屏
&& appInfo.targetSdkVersion >= O) { // targetsdkversion版本是Android8及以上
throw new IllegalStateException("Only fullscreen activities can request orientation");
}
複製程式碼
而是否是全屏的判斷依據是以下幾個主題屬性:
public static boolean isTranslucentOrFloating(TypedArray attributes) {
final boolean isTranslucent = attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent, false);
final boolean isSwipeToDismiss = !attributes.hasValue( com.android.internal.R.styleable.Window_windowIsTranslucent)
&& attributes.getBoolean( com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
final boolean isFloating = attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
return isFloating || isTranslucent || isSwipeToDismiss;
}
複製程式碼
問題到這裡看起來已經講清楚了,如果我們設定了以上幾個主題,並且鎖定了螢幕方向,那麼在Android8.0的手機上系統會直接丟擲異常。
解決方案
我們說說解決方法:
- targetsdkversion降低到26及以下
- 針對專案中的activity做一次檢查,避免指定透明主題的activity同時又指定了方向
基本上所有的解決方法本質上都是基於這兩種思路。好了,問題解決了。基本上網上關於相關問題的討論到這裡就結束了,比如下面這幾篇文章和討論:
java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
Only fullscreen activities can request orientation?一個搞笑的坑!
Kaola Mobile Team's Blog: Android O 適配詳細指南
當然,既然有了解決方案,所以一般分析到這裡也是可以理解的。
未解釋的問題
可是當我看到上面這些文章或問答,心裡還是有一些其他的疑問沒有被解答:
-
按照上面的分析,在targetsdkversion>=26的時候,在Android8.0手機上應該都有異常,但實際上targetsdkversion=26的時候是OK的,只有升級到27及以上才會崩
-
Android8以後真的解決了這個問題?
關於第一個問題,我繼續檢視了Android8.0的原始碼,以及它的提交記錄發現在這個提交不久之後,Android開發人員又有了新的提交,在sdk為26時,放開了限制。
Allow for SDK 26 Activities to specify orientation when not fullscreen
所以當我們設定的targetsdkversion<=26的時候沒有出現這個問題。只有在大於26的情況下,這個異常出現。
第二個問題,在Android8.1.0的第一個release版本中確實去掉了相關的程式碼,這個在Android8.1.0的release版本的提交紀錄裡能夠看得出來 傳送門
總結
從這個問題的產生和解決過程來看,確實可以說是Android系統開發人員的“手誤”了。但是說實話我很難想象會出現這樣的么蛾子,居然直接丟擲異常。難道他們不知道很多開發者都會在Activity裡指定透明主題和固定方向?而且提交了這種程式碼之後,在Android8.0系統更新說明裡居然也沒有提到。唉,好吧。