1. android 橫豎屏切換導致的onCreate執行兩次
最近開發一款手機播放器,節目列表界面是豎屏的,而播放界面需要是橫屏的。測試過程中,從播放界面退回到列表界面時,列表會重新載入,看了一下列印,回到列表界面後,onCreate居然又執行了,而且是執行了兩次。
按照activity的生命周期來說,onCreate一般只會執行一次的,從其他界面返回,居然還會再執行兩次,很奇怪的現象。
網上搜了搜,應該是跟橫豎屏切換有關,於是測試了一下。先把播放界面修改為豎屏,從播放界面返回後,列表界面正常,onCreate沒有被重復調用,說明onCreate的執行和橫豎屏切換是有關的。網上看到很多人說,在AndroidManifest.xml設置一下,添加 android:configChanges="orientation|keyboardHidden|screenSize" ,於是照做,再測試,果然解決問題。
2. Activity橫豎屏切換生命周期變化
onCreate ,
創建activity時調用。設置在該方法中,還以Bundle中可以提出用於創建該 Activity 所需的信息。
onStart ,
activity變為在屏幕上對用戶可見時,即獲得焦點時,會調用。
onResume ,
activity開始與用戶交互時調用(無論是啟動還是重新啟動一個活動,該方法總是被調用的)
onSaveInstanceState
onPause ,
activity被暫停或收回cpu和其他資源時調用,該方法用於保存活動狀態的
onStop ,
activity被停止並轉為不可見階段及後續的生命周期事件時,即失去焦點時調用
onDestroy ,
activity被完全從系統內存中移除時調用,該方法被調用可能是因為有人直接調用 finish()方法 或者系統決定停止該活動以釋放資源。
onRestoreInstanceState ,
Android在橫豎排切換時候,將主動銷毀activity和重新創建一個新的activity出來,在此過程中,onRestoreInstanceState就要被回調
onConfigurationChanged ,
配置指定屬性後,屏幕方向發生變化後回調此函數.
把該Activity添加
android:configChanges="orientation" ,
執行步驟3(切換成橫屏時)
android:configChanges="orientation" 對於4.04.0以上版本不生效
把該Activity添加 android:configChanges="orientation|screenSize" ,
執行步驟3(切換成橫屏時)
onConfigurationChanged-->
只列印onConfigChanged
把 android:configChanges="orientation|screenSize" 改成 android:configChanges="orientation|keyboardHidden|screenSize"
執行步驟3(切換橫屏幕)
只列印
onConfigChanged
執行步驟4(切換豎屏幕)
只列印onConfigChanged
切記一定要加上後邊的screenSize否則在4.0以上版本生命周期執行不生效。
當前Activity產生事件彈出Toast和AlertDialog的時候Activity的生命周期不會有改變
Activity運行時按下HOME鍵(跟被完全覆蓋是一樣的):
onPause --> onStop onRestart -->onStart--->onResume
Activity未被完全覆蓋只是失去焦點:onPause--->onResume
測試用手機版本5.1.1
Android實現屏幕旋轉方法
這種方法的優點:即使屏幕旋轉,Activity也不會重新onCreate。
缺點:屏幕只有一個方向。
這個方法的優點:我們可以隨時監聽屏幕旋轉變化,並對應做出相應的操作;
缺點:它只能一次旋轉90度,如果一下子旋轉180度,onConfigurationChanged函數不會被調用。
4.設置方向的其他方式
在AndroidManifest.xml設置
橫向顯示,但是基於設備感測器,既可以是按正常方向顯示,也可以反向顯示,在API Level 9中被引入。
android:screenOrientation="sensorLandscape"
縱向顯示,但是基於設備感測器,既可以是按正常方向顯示,也可以反向顯示,在API Level 9中被引入。
android:screenOrientation="sensorLandscape"
demo
3. 如何讓手機橫豎屏切換不重走Activity生命周期
擴展補充:
一:
Activity中還有一屬性和屏幕方向有關:
<activity
. . .
android:screenOrientation=["unspecified" | "user" | "behind" |
"landscape" | "portrait" |
"sensor" | "nosensor"]
. . .
</activity>
比如,在Mainifest.xml的Activity元素中增加這么一個屬性:
android:screenOrientation="portrait"
則無論手機如何變動,擁有這個屬性的activity都將是豎屏顯示。
android:screenOrientation="landscape「,為橫屏顯示。
4. Android屏幕配適、版本配適與多語言支持
目前主流的屏幕密度:240dpi (480 * 800px) , 320dpi (720*1280px) , 480dpi(1080*1920px)現在新出的手機幾乎全是全高清屏(1080*1920px)
Android圖片資源目錄
mdpi [1倍]160dpi
hdpi [1.5倍] 240dpi
xhdpi [2倍] 320dpi
xxhdpi [3倍] 480dpi
xxxhdpi [4倍] 640dpi
因此對其他圖片資源的建議是:
a.一般採用720 * 1280的屏幕尺寸設計,這樣切圖可以直接適配720 * 1280的機型。
b.720 * 1280下切的圖基本可以適配大部分機型。
d.適配480 * 800的機型,只需要把切圖 * 0.75。
e.適配1080 * 1920 的機型,只需要把切圖 * 1.50即可。
a.以720 * 1280作為設計標准,畫布大小定位720 * 1280 (以後1080*1920px做標准亦可,類推)
b.只使用偶數單位的尺寸
c.盡量只使用 24pt, 28pt , 32pt, 44pt大小的字體
d.設計完成之後,所有尺寸的px值除以2作為dp數據交給開發人員
e.三份切圖,分別是:xhdpi,hdpi,mdpi的資源,如果要切一份就使用xhdpi
柵格系統的最小單位是8dp,一切距離、尺寸都應該是8dp的整數倍,所有可操作元素最小點擊區域尺寸為48dp X 48dp。以下是一些常見的尺寸與距離:
有時候在自定義view,draw的時候單位往往是px,要做一個dpi的轉換,需要通過該類獲取屏幕的信息,如:屏幕密度,寬高等。
a.盡量使用線性布局(LinearLayout)和相對布局(RelateLayout),盡量不使用絕對布局(AbsoluteLayout)和幀布局(FrameLayout)。
b.盡量使用wrap_content、mach_parent讓view自適應或最大化,盡量不要寫寬高的值。
c.使用線下布局的百分比weight權重時,要把能伸縮方向的寬度寫成「0dp「,如果寫成wrap_coent會使布局效果不佳等問題。
d.盡量使用android的Shape自定義view背景,這樣會隨之自適應。
e.ImageView的ScaleType有幾種方式:matrix(默認)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY;盡量使用fitCenter按比例擴大至view寬度,能取得較好適配和顯示效果。(更多請參考: Android中的ImageView配適 )
f.獲取屏幕解析度信息,進行動態適配。(參考第三大點)
a.把屏幕設置成單一的橫屏或豎屏:
b.根據橫豎屏載入不同布局(android: screenOrientation="sensor")
通過this.getResources().getConfiguration().orientation來判斷當前是橫屏還是豎屏,然後在onCreate方法中載入不同的布局
採用第二種方式要注意的有兩點
布局問題:
需要在res目錄先建立layout-land和layout-port目錄相應的xml文件名字相同,然後在兩個文件夾下創建相同名字的兩套xml,系統就會根據不同的屏幕來進行自動尋找。
切換時activity的生命周期:
activity生命周期在切換橫豎屏會有一些有趣的變化
a.不設置activity的android:configChanges時,切換橫屏,activity的生命周期會重新調用一次,但是切換豎屏時,生命周期會重新調用兩次。
b.當設置activity的android:configChanges=「orientation」時,切換橫豎屏都會重新調用各生命周期一次。
c.當設置activity的android:configChanges=「orientation|keyboardHidden」(大於api13時,需要設為「orientation|screenSize」)時,切換橫豎屏不會重新調用各生命周期,只會調用onConfigurationChanged方法。
一般設為b或者c
平板應用的特性:
對於大屏幕的平板8英寸以上(參考ipad mini,現在很多高端手機都是5-6英寸了,8英寸以上視為平板吧),基與平板應用的特性,平板應用開發一般採取如下兩種策略
1)兼容模式
採用單activity(或者盡量少activity)+多fragment的結構開發應用,在layout資源文件中創建三套布局:手機布局、平板橫屏布局、平板豎屏布局。
優點:
只需要維護一個app
缺點:
設計及實現的難度變大,更復雜,有時候需要採取折衷方案
手機apk上由於含有平板的大解析度圖片資源(設計上可以減少內置資源)
2)開發另一套只適配平板的app
優點:
與手機app分離獨立。不會因為要兼容而採用一些折衷方案,影響其性能、內存
設計和實現更加自由
缺點:
需要維護兩套app
目前谷歌推薦第一種方案,但是國內很多應用是採取第二種方案。
可以通過判斷sdk的版本(Build.VERSION.SDK_INT),來為能夠使用的版本進行個性化設置
例如:沉浸式狀態欄配適
在Android系統4.4以前,狀態欄的背景色和字體顏色都是不能改變的。但是4.4以後Google增加了改變狀態欄背景透明的方法。可以通過判斷sdk的版本,來為能夠使用的版本進行個性化設置:
沉浸式狀態欄是Android在5.0中引入的,在5.0之前是沒有的,並且在Android6.0中沉浸式狀態欄的使用方法和5.0不一樣,因此需要做到版本兼容,針對於不同的Android進行適配,同樣也是通過判斷Build.VERSION.SDK_INT來區分版本,進行個性化配適
沉浸式狀態欄的實現方式有好幾種,更多請參考 沉浸式狀態欄的實現
原則:內置圖片資源不應該出現文字(如果出現文字需要具備)、所有的文字需要放在res資源目錄特定語言目錄下。
5. Android Activity生命周期都該做哪些事情
activity主要生命周期的方法說明: onCreate(Bundle savedInstanceState):創建activity時調用。設置在該方法中,還以Bundle的形式提供對以前儲存的任何狀態的訪問!
onStart():activity變為在屏幕上對用戶可見時調用。
onResume():activity開始與用戶交互時調用(無論是啟動還是重新啟動一個活動,該方法總是被調用的)。 onPause():activity被暫停或收回cpu和其他資源時調用,該方法用於保存活動狀態的,也是保護現場,壓棧吧!
onStop():activity被停止並轉為不可見階段及後續的生命周期事件時調用。
onRestart():重新啟動activity時調用。該活動仍在棧中,而不是啟動新的活動。 OnDestroy():activity被完全從系統內存中移除時調用,該方法被 2.橫豎屏切換時候activity的生命周期
1、新建一個Activity,並把各個生命周期列印出來
2、運行Activity,得到如下信息
onCreate-->onStart-->onResume-->
3、按crtl+f12切換成橫屏時
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
4、再按crtl+f12切換成豎屏時,發現列印了兩次相同的log
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
5、修改AndroidManifest.xml,把該Activity添加 android:configChanges="orientation",執行步驟3
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->
6、再執行步驟4,發現不會再列印相同信息,但多列印了一行onConfigChanged
onSaveInstanceState-->onPause-->onStop-->onDestroy-->onCreate-->onStart-->onRestoreInstanceState-->onResume-->onConfigurationChanged-->
7、把步驟5的android:configChanges="orientation" 改成 android:configChanges="orientation|keyboardHidden",執行步驟3,就只列印onConfigChanged
onConfigurationChanged-->
8、執行步驟4
onConfigurationChanged-->onConfigurationChanged-->
總結:
1、不設置Activity的android:configChanges時,切屏會重新調用各個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次
2、設置Activity的android:configChanges="orientation"時,切屏還是會重新調用各個生命周期,切橫、豎屏時只會執行一次
3、設置Activity的android:configChanges="orientation|keyboardHidden"時,切屏不會重新調用各個生命周期,只會執行onConfigurationChanged方法
總結一下整個Activity的生命周期
補充一點,當前Activity產生事件彈出Toast和AlertDialog的時候Activity的生命周期不會有改變
Activity運行時按下HOME鍵(跟被完全覆蓋是一樣的):onSaveInstanceState --> onPause --> onStop onRestart -->onStart--->onResume
Activity未被完全覆蓋只是失去焦點:onPause--->onResume
6. Android Activity橫豎屏切換生命周期
面試被問到橫豎屏切換時Activity的生命周期,正好記錄一下驗證過程~
橫豎屏切換涉及到的是Activity的android:configChanges屬性,而與其android:launchMode屬性沒有關系;
android:configChanges可以設置的屬性值有:
新建Activity,重寫各個生命周期方法:
運行Activity,生命周期如下:
切換橫屏,生命周期如下:
再切回豎屏,生命周期如下:
修改AndroidManifest.xml,添加 android:configChanges="orientation" 並切換橫屏,生命周期如下:
再切換豎屏,生命周期如下:
修改AndroidManifest.xml,屬性改為 android:configChanges="orientation|keyboardHidden|screenSize" ,切換橫屏,生命周期如下:
再切換回豎屏,生命周期如下:
7. 當Android設備屏幕由橫屏變成豎屏時Activity的生命周期是如何變化的
Android設備屏幕由橫屏變成豎屏時,實際上當前屏幕中的Activity要經歷的過程是:首摧毀當前Activityà重新創建一個Activity來適應屏幕的變化。那麼根據Activity的狀態變化分析我們可以看出它經歷的生命周期應該是:
在這個過程中最有可能讓大家產生誤解的就是:屏幕狀態變化時沒看到Activity消失,他實際上確實銷毀後又重新重建了。這些都是屬於Android的基礎知識,推薦你可以去個叫秒秒學的網站上看看,裡面有一些相關的課程,希望對你有幫助。
8. android 屏幕旋轉生命周期和setRequestedOrientation強制旋轉
屏幕會根據當前感測器進行自動旋轉,旋轉之後,activity屏幕的 生命周期不會發生變化 ,在activity中只會回調onConfigurationChanged方法
可見每次旋轉onDestory()方法都會被調用,如果要保存一些activity被銷毀前的數據的可以在onSaveInstanceState()方法中通過Bundle去保存
當我們調用了:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
或者
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
之後屏幕不會再自動旋轉回來的情況
關於這點:我在b站App端也發現相關問題,點進b站的播放視頻界面,我們手機開啟屏幕自動旋轉,當我們橫豎屏旋轉的時候是可以正常橫豎屏切換的,但是我們點擊視頻右下角的放大(就是橫屏)之後,自動旋轉就失效了,要豎屏的話需要再點擊一次
關於這個問題,就是我們說的setRequestedOrientation之後重力感測失效的問題,處理的方法也很簡單
在AndroidManifest.xml中設置了android:configChanges="orientation|keyboardHidden|screenSize的基礎上,在onConfigurationChanged中調用 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR) 方法,使其恢復重力感測即可