對Android開發者有益的40條優化建議

oschina發表於2013-09-16

  下面是開始Android程式設計的好方法:

  •  找一些與你想做事情類似的程式碼
  •  調整它,嘗試讓它做你像做的事情
  •  經歷問題
  •  使用StackOverflow解決問題

  對每個你像新增的特徵重複上述過程。這種方法能夠激勵你,因為你在保持不斷迭代,不經意中你學到了很多。然而,當你釋出應用時你還要做一些更深入的事情。

  從一些可正常工作的程式碼到一個可怕的應用程式是一個巨大的跳躍,相比iOS平臺Android更是如此 。當在iOS上釋出應用時只是在一個裝置上跳躍–你的手機–對很多裝置而言都很相似–同樣大小的螢幕,都有很好的硬體,95%上執行相同版本的作業系統。在Android應用中你不會遇到這種情況。

  你的程式必須能夠處理一切:從螢幕,處理器,定製的作業系統,API層級以及任何其他的特定裝置。

  這是我對使Android應用舒服起來的個人建議。

 目標螢幕尺寸及解決方法

  在Android世界裡目前有超過100種的不同螢幕尺寸,但解決方法也很豐富。為使你的應用適應不同的螢幕配置有兩件事情你需要確定:

  1. 你對不同的螢幕尺寸有一個好的佈局和結構
  2. 你的影像在不同解析度下工作良好

  這些都是獨立的任務,你可能有一個超級的tablet佈局,但上面的圖形看起來很糟糕。我們會依次討論他們。

 為不同的螢幕而設計

  1.通常會用ScrollView 和 ListView 輕鬆搞定

  當我們有一系列不同尺寸的大屏手機時,它們之間最大的不同就是螢幕的高度。因此ScrollView和ListView通常可是有效的工作,雖然有時它們並不能完全覆蓋全部螢幕。在OpenSignal中的Dashboard標籤下我們可以看到所有部件一氣呵成,不存在滑動、對於許多高階型別標籤中,滑動展示並不見得是一件壞事。如果你能夠為你所有的設計匹配到各種螢幕上面去,那麼最好不過。否則,這兩個控制元件會讓你用最小的開發代價來保證你的軟體在大多數螢幕上正常展示。

opensignal_dashboard1

  Dashboard style 的設計不需要scroll

  2: 使用資料夾. Android 的資原始檔夾結構非常強大, 它允許開發者將不同的圖片、字串、佈局檔案、外形、顏色這些資源,在api、程式碼、螢幕尺寸等部分. 下面是一個例子,展示了在資原始檔夾下你可以怎樣做:

Screen Shot 2013-07-29 at 10.32.18

  在 values-small 資料夾中存放了一個 bools.xml 檔案, 檔案中有如下幾行程式碼:

<resources>
<bool name="small_screen">true</bool>
</resources>

  在程式碼中我可這樣引用:

if(getResources().getBoolean(R.bool.small_screen)){
getSupportActionBar().hide();
}

  在小尺寸裝置中boolean值將置為true 我此時將因此ActionBar來節省空間. 這段程式碼正是非凡的ActionBarSherlock 擴充套件庫中的一部分,稍後再詳細介紹. 在values-sw360dp資料夾中,存放對應螢幕寬於360dp的資原始檔。與上面相同的位置,有如下程式碼

<resources>
<bool name="small_screen">false</bool>
</resources>

  對於大螢幕而言,ActionBar就置為了顯示狀態.

  我不需要將 bools.xml 檔案放入 values-sw400dp資料夾中, 因為作業系統會自動按相應路徑搜尋. 例如一個裝置寬 600dp (600/160=3.75 英寸, 這就是我們通常所說的7片裝) 作業系統會在values-sw600dp 和其包含的的資料夾中搜尋 bools.xml 檔案, 若沒有找到則搜尋 values-sw400dp 資料夾,在搜尋 values-sw360dp 資料夾以此類推.

  建議3:160dp = 1英寸。320 dp = 2英寸。dp = dip

  建議4:你可以用這些目錄結構技巧來應付所有資源型別,比如你的XML佈局用指定的系統目錄名稱

  來解決這個問題,如:layout-sw360dp目錄可以匹配目標寬是360dp的機器。如果你也要支援橫豎屏佈局切換的話,可以用如下目錄:

  layout-sw360dp-land

  layout-sw360dp-port

  別急,你有一半的使用者是說阿拉伯語的?那就將佈局名稱改為下面的樣子吧:

  layout-sw360dp-land

  layout-sw360dp-port

  layout-sw360dp-land-ar

  layout-sw360dp-port-ar

  前兩個可以適用於所有語言,-ar代表阿拉伯語。

  建議5:資源規則簡介:

  XXX //例子:沒有新增目錄名:預設-適用於Nexus One,Droid 2,S2

  XXX-sw360dp // 比較大的手機 – Galaxy Nexus, S3, S4

  XXX-sw600dp // 7〃 平板

  XXX-sw720dp // 10” 平板

  在Kindle裝置有些不同,如下:

  XXX-large-mdpi // kindle fire 7〃

  XXX-large-hdpi // kindle fire 7〃 HD

  建議6:如果你不想裁剪所有的佈局檔案,你可以用dimens.xml檔案。你要是留心我上面的文章,你就會注意到在我的values目錄裡有很多dimens.xml,這樣是因為我更喜歡在一個layout.xml裡設定值,在每一個佈局檔案裡我喜歡這樣做:

<ImageView
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/small_margin"
android:layout_width="@dimen/dashBoardWidth"
android:layout_height="@dimen/dashBoardHeight"
android:id="@+id/dashboard"/>

small_margin是在dimen.xml檔案裡定義的:

<resources>

<dimen name="small_margin">4dp</dimen>
</resources> 

  這個4dp變數在所有dimen檔案裡。我有個Excel檔案,裡面建立了所有不同的基於不同因素所需的尺寸定義。也許你會問:為什麼不讓android OS來處理所有尺寸的問題?為什麼不呢,為什麼不用一個values目錄和一個佈局目錄來代替所有寫死的數值呢?那當然是可以的,如果設定得當,都會得到所有的尺寸,但是對於有些元素看起來就不是那麼好計算尺寸了。

  建議7:讓空白空間大於影像空間。讓影像空間大於按鈕的大小。如果將按鈕,多選框,切換控制元件放大後是很醜陋的。一個100dip(0.63")大小的按鈕是不想在平板上顯示為原來兩倍寬度200dip(1.25")的.原因是螢幕變大了,這不是說平板是給巨人用的。我們可以這樣做,在按鈕增加的空間和圖片擴充套件的空間裡新增空白。

  建議8:用GraphicalLayout工具快速預覽。GraphicalLayout是WYSIWG XML編輯器。我喜歡直接編寫元素-而不是拖,丟棄的可見程式設計方式,但在新增一些元素之後,可以在GraphicalLayout的下拉選擇選單裡選擇不同螢幕尺寸進行測試。


  這裡有很多選項供你選擇。

 圖片縮放

  建議9:不要把所有的圖片都縮放了。用佈局檔案來適應不同螢幕尺寸的方法只是成功的一半,佈局裡的元素(如:圖片)也要能在高解析度的螢幕下良好工作。在概念上比較簡單的方式就是建立一套完整的圖片目錄並將它們與很多drawable目錄匹配起來。

  drawable-sw600dp-ldpi
  drawable-sw600dp-mdpi
  drawable-sw600dp-hdpi
  drawable-sw600dp-xhdpi
  drawable-sw600dp-xxhdpi
  ...其它的類似。

  不要這樣做:

  你不要太盡信書了。

  一般來說有drawble-ldpi, drawable-hdpi等目錄就足夠了,不需要將所有的情況都加上。

  建議10:避免使用點陣圖(jpg,png)。對於一些圖示來說,用點陣圖是個不錯的選擇,因為它們使用簡單。但是如果可以避免使用點陣圖,你可以節省很多空間。但用不同的方法也可以達到很好的結果。

  建議11:用XML繪圖。點陣圖都可以用XML繪圖來代替的。XML繪圖不是萬能的,但是它的方便性還是使我感到驚訝。Android開發文件中有詳細的介紹,這裡有個簡單的例子:

<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners
android:bottomRightRadius="14dp"
android:bottomLeftRadius="14dp"
android:topLeftRadius="14dp"
android:topRightRadius="14dp"/>
<gradient
android:startColor="@color/off_white"
android:endColor="@color/pale_yellow"
android:angle="270"
android:type="linear"/>
<stroke
android:width="4dp"
android:color="@color/osm_darkerblue"/>
</shape>

  這裡是定義了一個圓角矩形,一個有漸變的邊(深藍)。你可以在佈局檔案的任何地方來引用,而且它可以適應於任何螢幕。用它可以做出理想的按鈕。

  建議12:用更多的XML繪圖。再來介紹一個用XML繪圖製作出能更加讓你興奮的例子,下面的雷達背景看起來是不是更加的複雜:

  不用點陣圖對你的UI是沒有壞處的(除過圖示)。

  建議13:仍然用更多的XML繪圖(如果必須,就用點陣圖)。那我們怎樣為天氣訊號構建一個超酷的圖示-讓燈泡動態的依據光的強度來進行自動填充,以及怎麼點選指標後讓其旋轉呢?這裡我們用點陣圖和XML結合起來做個例子:

  燈泡我們用PNG圖:icon_magnitude_min(一個空的燈泡)和icon_magnitude_max(充滿光的燈泡),然後我們動態的裁剪後者。為了實現這個目標我是這樣做的:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/icon_magnitude_min"
/>
<item >
<clip
android:clipOrientation="vertical"
android:drawable="@drawable/icon_magnitude_max"
android:gravity="top"
/>
</item>
</layer-list>

  在java程式中我將得到回形針的引用,然後可以用它來控制光的強度。

  建議14: 為什麼要用9-patch (當你可以用XML drawables的時候)? Android具有使用9-patches 來定義drawables的選擇,有些教程闡述了怎樣用它們來做一個按鈕,這樣可以在伸展的時候保持幾個角不變 (並且避免了畫素處理)。如果你已經知道怎樣使用9-patches,可能是從web設計中學會的,那麼它們或許值得一用。如果你對9-patches並不熟悉,我建議你維持原樣。如果你想適應什麼東西——例如拐角的圓弧或者顏色,建立9個小塊要比建立點陣圖更多被涉及,這就像回到了影像編輯器的時代。許多用9-patches獲得的效果也可以通過XML獲得。

 建議15: 通過覆蓋onDraw()建立自定義views. 有些事情XML並不十分在行,我們在OpenSignal和WeatherSignal中畫過許多影像,為此有許多的庫,但是我們要為自定義影像自己編寫程式碼。這很有趣。或許你永遠也不需要做這個,但為了使影像高度動態並自定義,這經常是唯一可行的辦法。

  建議16:在不能使用XML的地方使用SVG. 有時候覆蓋onDraw()並勤勤懇懇的為自定義view編寫程式碼畫出需要的線條與弧線是過於技術化了。畢竟有一種向量影像語言,它稱作…Scalable Vector Graphics(可擴充套件向量圖形)。它也是史上最酷的Android應用之一—Androidify的動力來源。事實上他們建立這個庫就是為了那款應用,他們將它釋出在這裡:SVG for Android  。這也就是我們在OpenSignal中畫儀表盤所用到的。

  建議17: 對SVG檔案GZip壓縮. 將它們變得更小它們就會處理的更快。

  建議18: SVG庫並不是支援一切. 在一些特定的alpha通道中似乎不能正常工作,你甚至不得不在程式碼中將它們剔除。

 達到在android所有版本里表示展現一致的目標

  建議19:在一些android系統裡(如TouchWhizz/HTC Sense/MotoBlur等等),預設的buttons和其他UI元件會跟原生系統裡的看起來差別很大。我希望這不是真的,但事實卻是如此。

  建議20:自定義你的UI元件。為了確定你的app在所有的裝置裡看起來是一致的,你將需要自定義所有的東西。這其實沒有你想象中那麼難,只要你做到了,你將能更加好地把握到你的app的展示外觀。

  建議21:Selectors是建立buttons的利器。我們在上面提到了如何在XML裡定義button的背景,但是你將如何建立一個當按下去會改變的button呢?很簡單:像下面那樣在xml檔案裡定義背景。該xml檔案將接收到button當前狀態並且在外觀上做出相應的改變。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/btn_bg_selected" />
<item android:state_focused="true" android:drawable="@drawable/btn_bg" />
<item android:drawable="@drawable/btn_bg" /> <!-- default -->
</selector>

  建議22:在Honeycomb之前的版本里時不存在ActionBar跟很多 animation  樣式的,所以可以使用ActionBarSherlock 跟NineOldAndroids來代替。Jake Wharton寫的Android開源 元件都是往下相容的精心傑作。更為驚喜的是,ABS 擁有強大的功能用來定義ActionBar。

  把速度作為目標

  建議23:在執行慢的手機上測試。你將在執行慢的手機上發現很多問題,同時它讓你抓狂,沒人會喜歡執行慢的程式。

  建議24:儘量減少XML佈局層次。更多的層次意味著系統將為解析你的程式碼付出更多的工作,這將會讓影像渲染的更慢。

  建議25:用Android Lint。在工程目錄上右鍵選擇Eclipse>Android Tools>Run Lint。它將會得到程式的一些資訊,並能提高程式的執行速度,或者它能讓你得程式碼更加清爽。

  建議26:Android Lint可以得到錯誤資訊。它可以給你的程式碼提供很詳細的資訊,並在你出錯之前就可以給做出提示。

  建議27:用<merge>可以幫助你減少檢視層次結構。這是一種簡單的方式來去除多餘的層次。好的文章都對此有所解釋,而且在 Android Developer中它也顯得與眾不同。

  建議28:用HierarchyViewer可以直觀的看到你佈局的層次。這個智慧的工具可以顯示佈局中有多少層次,而且可以提示出那些可以讓程式變慢。

  建議29:如果可以儘量用RelativeLayoutAbsoluteLayout已經過期了,就不要用了。你經常會遇到在RelativeLayout和LinearLayout中做出選擇的情況,那就直接用RelativeLayouot吧,因為它可以讓你減少檢視層次。比如,你想實現一個如下檢視:

  盒子 A 在螢幕左半邊 |盒子 B在螢幕右半邊

  你首先會想到這麼做:

<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:orientation=”horizontal”
>
<TextView
android:text=”Box A takes up left half of the screen”
android:layout_width=”0dip”
android:layout_height=”wrap_content”
android:layout_weight=”1″
/>
<TextView
android:text=”Box B takes up left half of the screen”
android:layout_width=”0dip”
android:layout_height=”wrap_content”
android:layout_weight=”1″
/>
</LinearLayout>
That works just fine, but you could also use:
<RelativeLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:orientation=”horizontal”
>
<TextView
android:text=”Box A takes up left half of the screen”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_toLeftOf=”@+id/dummy_center”
/>
<View
android:id=”@+id/dummy_center”
android:layout_width=”0dip”
android:layout_height=”0dip”
android:layout_gravity=”center”
/>
<TextView
android:text=”Box B takes up left half of the screen”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_toRightOf=”@+id/dummy_center”
/>
</RelativeLayout>

  第二個表單比第一個難看的多,事實上是相當的糟糕:我們已經介紹過一個完整的新元素了。但是假如我們要給每個盒子裡加入一個圖片,一般的我們將這樣做:

  盒子 A 在螢幕左半邊 圖片|盒子 B在螢幕右半邊 圖片

  用第一中方法,你得建立一個有兩個層次的LinearLayout,如果用第二種方法,你可以直接在同一個RelativeLayout中加入圖片,比如要指定第一個圖片必須在“dummy_center”的左邊,而且一個TextView A必須也在其左側。那麼你就得用7個元素3個檢視層次了(LinearLayout 方式),而(RelativeLayout方式)只用6個元素2個層次,這樣所有的工作新增完成。

  建議30:用一些擴充套件工具如DDMS。這可以幫助你發現一些不必要的網路呼叫、檢視電池使用量、垃圾回收資訊,狀態變化(例子:當回撥onStop和onDestroy時)等。LittleEye是我目前比較喜歡的工具。

  建議31:用AsyncTasks。Anroid工程團隊受夠了人們經常在UI執行緒裡面實現網路呼叫(譯註:耗時操作,容易阻塞UI重新整理),所以他們實現了一些可產生編譯級錯誤資訊的API。但是仍然在很多app中的一些工作會拖垮UI執行緒,我們要考慮到UI佈局要快以及提高UI的響應性。

  目標機器空間小

  建議32:一些Aandroid裝置有100mb空間大小的限制。現在情況已有變化了,但是仍然有很多使用者還會擔心5Mb大小的app會浪費空間。如果你可以選擇將app裝入SD卡的話,這就不是問題了,但如果你的app需要在onBoot裡啟動的話你就不能裝入SD卡了(例子:如一些窗體小部件).甚至對於一些新的裝置,如果能很快的下載一個小的APK的話,使用者還是很高興的。

  建議33:用XML資源(我發誓上次我已經提醒過了),這將比PNG資源節省很多空間,當你僅僅需要一個可以滿足很多螢幕大小的配置時,一個XML檔案會比能實現同樣功能的PNG省空間。

  建議34:如果要用PNG,最好優化一下(用PNGCrush或ImageOptim)
 

  目標bugs

  建議35:在Android開發者控制檯裡檢查所有被自動檢測出來的bugs. 

  建議36: ProGuard現在是預設啟動著的. Proguard太好用了 (提高你app的速度和降低檔案大小),但這也讓StackTraces 非常難以處理。你將需要重新追蹤你的StackTraces,因此你將需要繼續保留在每次構建中建立的Proguard的對映檔案。我把它們都放到以程式碼版本號命名的資料夾裡。

  建議37: 為了顯示StackTraces裡的行數,你需要修改ProGuard的配置。確認你的proguard.cfg擁有下面這句話:
-keepattributes SourceFile,LineNumberTable

  建議38:使用staged rollouts。測試5%的基礎使用者,並且觀察bug報告。

  建議39:使用真實裝置測試平臺。Device Anywhere and Perfecto Mobile提供了虛擬測試平臺,在那裡,你可以使用真正的移動裝置。我發現他們有一些笨拙,加入連續不斷地進行測試的話,會導致有一些糟糕的情況。如果你在聯合辦公的環境裡工作,或者有一些Android開發的好友,那麼去啟動一個“裝置池”吧。

  建議40: 多寫程式碼少寫部落格。其實不是的, 分享就是關愛, 我只是想不出第40條寫什麼是了。

  原文地址:http://opensignal.com/blog/2013/07/30/40-developer-tips-for-android-optimization/

相關文章