各自的定義:
- px:pixel,像素,屏幕上實際的像素點單位
- dpi: dot per inch,每英寸多少點,該值越高,則圖片越細膩
- dp: dip,Density-independent pixel, 設備獨立像素
- sp: scale-independent pixel,字體大小單位。
像素密度爲160時,1dp = 1px
px = dp*(dpi/160) = dp*density
適配方法
- 使用wrap_content, match_parent, weight要確保佈局的靈活性並適應各種尺寸的屏幕
- 使用RelativeLayout或ConstraintLayout,禁用絕對佈局。
- 使用Nine-Patch圖片
- 使用Size限定符
- 使用Smallest-width限定符
卡頓的兩大因素:
界面繪製:主要原因是繪製的層級深、頁面複雜、刷新不合理,由於這些原因導致卡頓的場景更多出現在 UI 和啓動後的初始界面以及跳轉到頁面的繪製上。
數據處理:導致這種卡頓場景的原因是數據處理量太大,一般分爲三種情況,一是數據在處理 UI 線程,二是數據處理佔用 CPU 高,導致主線程拿不到時間片,三是內存增加導致 GC 頻繁,從而引起卡頓。
佈局優化
- 使用ConstraintLayout或者RelativeLayout,ConstraintLayout開銷較小,儘量減少佈局的重疊和嵌套。
- 父佈局的寬和高儘量設置成固定值或者match-parent,因爲這樣在測量尺寸時只需要測量一次。wrap_content,會增加measure計算成本,子View的尺寸可能會動態變化,這樣就造成了父佈局的尺寸需要多次被測量,影響性能。
- 刪除控件中無用屬性
- 通用的佈局抽出來通過include包含到指定的佈局。這樣可以實現佈局的複用,既可以提高佈局性能,也有利於以後的維護。用include時候需要注意,如果想重寫被包含佈局的layout屬性必須在include標籤內重寫layout_width和layout_height屬性,這樣重寫其它layout屬性纔有效。
- 如果include標籤的外層不是根佈局,用merge實現,這樣可以減少一層嵌套。用merge實現的佈局被include包含後就不能重寫其layout屬性了(因爲merge節點不是一個佈局),所以這時候你想對整個被包含佈局進行操作(比如設置間距),那麼只能在include標籤外層包一層佈局(比如RelativeLayout),通過該佈局來對被包含佈局進行整體操作
- ViewStub實現懶加載佈局。View.GONE方式在Inflate佈局的時候View仍然會創建對象,會實例化。通過ViewStub就可以真正實現需要時才加載佈局。
自定義View優化
- 減少不必要的代碼
- 不在 onDraw 中做內存分配的事
- 減少 onDraw 被調用的次數,調用視圖的setVisibility()、setEnabled()、setSelected()等都會導致視圖重繪,如果想要手動地強制讓視圖進行重繪,可以調用invalidate() 來實現。invalidate()只會重調onDraw方法,onMeasure和onLayout不會。postInvalidate方法應用在非UI線程中
- 減少 requestLayout 的次數,該方法會重調onDraw,onMeasure和onLayout3個方法。
節省——耗電優化
- 計算優化
- 避免 Wake Lock 使用不當
冷啓動與熱啓動
冷啓動
在啓動應用時,系統中沒有該應用的進程,這時系統會創建一個新的進程分配給該應用;
熱啓動
在啓動應用時,系統中已有該應用的進程(例:按back鍵、home鍵,應用雖然會退出,但是該應用的進程還是保留在後臺)
區別:
- 冷啓動:系統沒有該應用的進程,需要創建一個新的進程分配給應用,所以會先創建和初始化Application類,再創建和初始化MainActivity類(包括一系列的測量、佈局、繪製),最後顯示在界面上。
- 熱啓動: 從已有的進程中來啓動,不會創建和初始化Application類,直接創建和初始化MainActivity類(包括一系列的測量、佈局、繪製),最後顯示在界面上。