Android App优化之Layout怎么摆
Android App優(yōu)化之Layout怎么擺
anly_jun關(guān)注
0.1172016.09.03 00:34:00字?jǐn)?shù) 1,668閱讀 15,750
系列文:
優(yōu)化完App的啟動(dòng)速度, 接下來(lái)我們要關(guān)注的就是UI布局怎么更高效了.
欲善其事, 先利其器. 分析布局, 就不得不用到Hierarchy Viewer了.
本文工具使用皆以GithubApp的詳情界面RepoDetailActivity為例說(shuō)明.
為了不影響閱讀體驗(yàn), 對(duì)應(yīng)的布局文件activity_repo_detail.xml的代碼放在文末
1, Hierarchy Viewer怎么用
Hierarchy發(fā)音 [美: 'ha??rɑrki] [英: 'ha??rɑ?k?] 層次結(jié)構(gòu)的意思.
之前一直念不順這個(gè)單詞Hierarchy, 就簡(jiǎn)稱(chēng)為H Viewer了. 下文就這么簡(jiǎn)稱(chēng)吧.
如官網(wǎng)描述, H Viewer是用來(lái)分析調(diào)試和優(yōu)化我們的UI的一個(gè)圖形化工具. 它會(huì)展示當(dāng)前界面的View層級(jí).
1.1 啟用H Viewer
比較早接觸Android開(kāi)發(fā)的同學(xué)可能知道, H Viewer只能在root過(guò)的機(jī)器才能使用. 主要是在沒(méi)有root過(guò)的機(jī)器中view server這個(gè)服務(wù)是沒(méi)有開(kāi)啟的. H Viewer就無(wú)法連接到機(jī)器獲取view層級(jí)信息.
正所謂高手在民間, 大家都嘗試在未root的機(jī)器中啟用view server來(lái)使用H Viewer. 最具代表性的就是romainguy的ViewServer, 只需集成少量代碼到你的Activity, 相當(dāng)于在手機(jī)端開(kāi)啟了view server服務(wù), 建立socket通道與PC端的H Viewer通信.
此工程被Android官網(wǎng)吸收, 作為開(kāi)啟H View的方案之一.
完整開(kāi)啟H Viewer的套路如下:
- 4.0及以下, 沒(méi)有root. 使用上述的開(kāi)源工程ViewServer提供的方式.
- 4.0及以下, 已經(jīng)root. 無(wú)需其他額外設(shè)置.
- 4.1及以上. 需要在PC端設(shè)置ANDROID_HVPROTO環(huán)境變量.
設(shè)置系統(tǒng)環(huán)境變量: ANDROID_HVPROTO, 值為ddm
具體設(shè)置系統(tǒng)環(huán)境變量根據(jù)PC系統(tǒng)不同而異.
做完上述配置后, 你就可以打開(kāi)H Viewer了, 打開(kāi)DDMS, 如下操作進(jìn)入H Viewer界面:
?
ddms_open_hviewer
1.2 H Viewer界面詳解
以GithubApp的詳情界面RepoDetailActivity為例說(shuō)明:
Snip20160902_1.png
界面分為四個(gè)部分:
Window
顯示當(dāng)前連接的設(shè)備和供分析的界面. 可手動(dòng)選擇.
Tree View
樹(shù)狀圖的形式展示該Activity中的View層級(jí)結(jié)構(gòu). 可以放大縮小, 每個(gè)節(jié)點(diǎn)代表一個(gè)View, 點(diǎn)擊可以彈出其屬性, 當(dāng)前值, 并且在LayoutView中會(huì)顯示其在界面中相應(yīng)位置.
Tree View是我們主要要分析的視圖.
Tree Overview
Tree View的概覽圖. 有一個(gè)選擇框, 可以拖動(dòng)選擇查看. 選中的部分會(huì)在Tree View中顯示.
Layout View
匹配手機(jī)屏幕的視圖, 按照View的實(shí)際顯示位置展示出來(lái)的框圖.
1.3 H Viewer參數(shù)解讀
14728281715494.jpg
關(guān)于三個(gè)小圓點(diǎn)的性能指示, 在App優(yōu)化之性能分析工具一文中有提到, 再?gòu)?qiáng)調(diào)一遍:
三個(gè)小圓點(diǎn), 依次表示Measure, Layout, Draw, 可以理解為對(duì)應(yīng)View的onMeasure, onLayout, onDraw三個(gè)方法.
- 綠色, 表示該View的此項(xiàng)性能比該View Tree中超過(guò)50%的View都要快.
- 黃色, 表示該View的此項(xiàng)性能比該View Tree中超過(guò)50%的View都要慢.
- 紅色, 表示該View的此項(xiàng)性能是View Tree中最慢的.
如果你的界面的Tree View中紅點(diǎn)較多, 那就需要注意了. 一般來(lái)說(shuō):
1, Measure紅點(diǎn), 可能是布局中嵌套R(shí)elativeLayout, 或是嵌套LinearLayout都使用了weight屬性.
2, Layout紅點(diǎn), 可能是布局層級(jí)太深.
3, Draw紅點(diǎn), 可能是自定義View的繪制有問(wèn)題, 復(fù)雜計(jì)算等.
由上圖, 可以看到我們的RepoItemView的三項(xiàng)指標(biāo)都不合格, 證明其還有很多優(yōu)化空間. 層級(jí), 繪制都可以優(yōu)化.
除了用H Viewer來(lái)做代碼后分析, Android還提供了Lint, 在我們編寫(xiě)xml布局文件時(shí)就即時(shí)的給出一些相關(guān)提示.
2, Lint tool
打開(kāi)RepoDetailActivity的布局文件activity_repo_detail.xml, 在Android Studio菜單欄中開(kāi)啟Lint檢查:
14728313149102.jpg
選擇當(dāng)前文件:
14728313382536.jpg
會(huì)在下方彈出分析結(jié)果:
14728314908964.jpg
分析結(jié)果包括用法檢測(cè)(例如版本特有屬性), 國(guó)際化(字符串是否提取到strings.xml, Rlt支持等), 以及我們今天的主題---性能分析結(jié)果.
點(diǎn)開(kāi)"Android -> Lint -> Performance"項(xiàng), 可以看到關(guān)于布局性能的建議項(xiàng). 此例中是說(shuō)ScrollView的父級(jí)LinearLayout是不必要的.
3, 怎么優(yōu)化你的布局
通過(guò)以上工具的使用和分析, 也基本能找到布局的一些常見(jiàn)的好與不好的了.
正所謂授之以魚(yú)不如授之以漁. 在此也就不太詳細(xì)去講怎么優(yōu)化了, 幾點(diǎn)建議, 大家自行實(shí)踐吧:)
盡量減少布局層級(jí)和復(fù)雜度
善用Tag
使用include來(lái)重用布局.
使用<merge>來(lái)解決include或自定義組合ViewGroup導(dǎo)致的冗余層級(jí)問(wèn)題. 例如本例中的RepoItemView的布局文件實(shí)際可以用一個(gè)<merge>標(biāo)簽來(lái)減少一級(jí).
ListView優(yōu)化
4, 附示例代碼
因github上的源碼會(huì)持續(xù)更新, 特留對(duì)應(yīng)代碼在此.
activity_repo_detail.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayoutandroid:id="@+id/root_layout"xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/md_white_1000"android:orientation="vertical"android:padding="@dimen/dimen_10"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:fillViewport="true"android:scrollbars="none"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><com.anly.githubapp.ui.widget.RepoItemViewandroid:id="@+id/repo_item_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/md_grey_300"android:elevation="@dimen/dimen_2"/><LinearLayoutandroid:id="@+id/contributor_layout"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="@dimen/dimen_10"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"android:orientation="horizontal"android:background="@drawable/button_bg"android:paddingLeft="@dimen/dimen_10"><TextViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center_vertical"android:text="{oct-organization} Contributors"/><TextViewandroid:id="@+id/contributors_count"android:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"/></LinearLayout><android.support.v7.widget.RecyclerViewandroid:id="@+id/contributor_list"android:layout_width="match_parent"android:layout_height="@dimen/dimen_60"android:layout_marginTop="@dimen/dimen_2"/></LinearLayout><LinearLayoutandroid:id="@+id/fork_layout"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="@dimen/dimen_10"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"android:orientation="horizontal"android:background="@drawable/button_bg"android:paddingLeft="@dimen/dimen_10"><TextViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:gravity="center_vertical"android:text="{oct-gist_fork} Forks"/><TextViewandroid:id="@+id/forks_count"android:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"/></LinearLayout><android.support.v7.widget.RecyclerViewandroid:id="@+id/fork_list"android:layout_width="match_parent"android:layout_height="@dimen/dimen_60"android:layout_marginTop="@dimen/dimen_2"/></LinearLayout><LinearLayoutandroid:id="@+id/code_layout"android:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"android:orientation="horizontal"android:layout_marginTop="@dimen/dimen_10"android:background="@drawable/button_bg"android:paddingLeft="@dimen/dimen_10"><TextViewandroid:id="@+id/code_label"android:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"android:text="{oct-file_code} Code"/></LinearLayout><LinearLayoutandroid:id="@+id/readme_layout"android:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"android:orientation="horizontal"android:layout_marginTop="@dimen/dimen_10"android:background="@drawable/button_bg"android:paddingLeft="@dimen/dimen_10"><TextViewandroid:id="@+id/readme_label"android:layout_width="match_parent"android:layout_height="@dimen/dimen_40"android:gravity="center_vertical"android:text="{oct-info} README"/></LinearLayout></LinearLayout></ScrollView> </LinearLayout>com.anly.githubapp.ui.widget.RepoItemView對(duì)應(yīng)的布局:
<?xml version="1.0" encoding="utf-8"?> <FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:padding="@dimen/dimen_10"><TextViewandroid:id="@+id/name"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="left|center_vertical"android:maxLines="1"android:text="@string/app_name"android:textColor="@android:color/black"android:textSize="@dimen/text_size_18"/><TextViewandroid:id="@+id/desc"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="left|center_vertical"android:maxLines="2"android:text="@string/app_name"android:textColor="@android:color/darker_gray"android:textSize="@dimen/text_size_12"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="@dimen/dimen_5"android:gravity="center_vertical"android:orientation="horizontal"><ImageViewandroid:id="@+id/image"android:layout_width="@dimen/dimen_32"android:layout_height="@dimen/dimen_32"android:scaleType="centerInside"android:src="@mipmap/ic_launcher"android:visibility="visible"/><TextViewandroid:id="@+id/owner"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginLeft="@dimen/dimen_10"android:gravity="left|center_vertical"android:text="@string/app_name"android:textColor="@android:color/black"android:textSize="@dimen/text_size_14"/></LinearLayout><Viewandroid:layout_marginTop="@dimen/dimen_5"android:layout_width="match_parent"android:layout_height="1px"android:background="@color/grey"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="@dimen/dimen_32"android:gravity="center_vertical"android:orientation="horizontal"android:paddingTop="@dimen/dimen_10"><TextViewandroid:id="@+id/update_time"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="left|center_vertical"android:text="@string/app_name"android:textColor="@android:color/black"android:textSize="@dimen/text_size_12"/><Viewandroid:layout_width="1px"android:layout_height="match_parent"android:background="@color/grey"/><LinearLayoutandroid:id="@+id/star_view"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:orientation="horizontal"><ImageViewandroid:id="@+id/star_icon"android:layout_width="@dimen/dimen_16"android:layout_height="@dimen/dimen_16"android:scaleType="centerInside"android:src="@drawable/ic_star"/><TextViewandroid:id="@+id/star"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_marginLeft="@dimen/dimen_5"android:gravity="center"android:text="@string/app_name"android:textColor="@android:color/black"android:textSize="@dimen/text_size_12"/></LinearLayout></LinearLayout></LinearLayout><com.flyco.labelview.LabelViewandroid:id="@+id/label_view"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"app:lv_background_color="@color/md_yellow_500"app:lv_gravity="TOP_RIGHT"app:lv_text="TEST"app:lv_text_size="@dimen/text_size_12"/> </FrameLayout>優(yōu)化不同于做功能, 可能分析的多, 出的成果少~ 比較枯燥, 然而優(yōu)化也是App發(fā)展的必經(jīng)之路, 歡迎大家分享經(jīng)驗(yàn).
轉(zhuǎn)載請(qǐng)注明出處, 歡迎大家分享到朋友圈, 微博~
總結(jié)
以上是生活随笔為你收集整理的Android App优化之Layout怎么摆的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 怎样将多个视频快速分割成两段或者多段
- 下一篇: Linux下文件的操作