40條Android開發優化建議
以下是開始Android編程的好方法:
1、找一些與你想開發的功能類似的代碼
2、調整它,嘗試讓它變成你想要的
3、回顧開發中遇到的問題
4、使用StackOverflow來解決遇到的問題
對每個你想實現的東西重復上述過程。采用這種方法能夠激勵你,因為你在保持不斷迭代更新,在這個過程里面你會學到很多。當然,當你發布應用的時候你還要去做一些更深入的東西。
從一些能夠正常編譯的代碼到成為一個應用程序,這是一個質的飛躍,比起iOS,Android則表現的更加明顯。當iOS應用發布的時候,實際上只是在一種設備之間跳躍,對iOS很多機型而言都很相似,同樣大小的屏幕,并且都有良好的硬件支撐,95%上機型運行相同版本的iOS操作系統。然而在Android應用中,并不會遇到這種情況。
我們的程序必須能夠應對一切:包括不同的屏幕、處理器、定制操作系統、API以及其他任何帶Android操作系統的設備。
以下是我認為對Android比較好的一些建議。
目標屏幕尺寸及解決辦法
在Android的大世界里有超過100種不同的屏幕尺寸,當然,解決屏幕適配的方法也很多。為了進行Android的屏幕適配,你需要確定以下兩件事情:
1、對不同的屏幕分辨率和尺寸有一個良好的布局和結構來適應它
2、UI圖像能夠適應不同分辨率的手機
這些都是獨立的任務,也許你有一個超級的tablet布局,但布局上的圖片看起來很糟。接下來我會依次討論它們。
為不同的屏幕尺寸設計布局
1、一般用ScrollView+ListView輕松搞定它
當我們有一系列不同屏幕尺寸的手機時,它們之間最大的不同就是屏幕的高度。因此ScrollView和ListView通常顯示良好,雖然有時侯它們并不能完全覆蓋整個屏幕。在OpenSignal中的Dashboard標簽下我們可以看到所有東西,他們不需要滑動,然而對于許多高級控件來說,滑動展示并非一件壞事。如果你能夠讓你的應用適配各種不同尺寸的手機,那就很完美了,否則這兩個控件會讓你用最小的代價來保證你的應用適配大多數不同的屏幕尺寸。
Dashboard風格的就不需要滾動
2、使用文件夾結構
Android 的res文件夾結構非常強大, 它允許開發者更改圖片、文字、布局文件、尺寸規格、顏色等資源。下面的例子展示了在res文件夾的用處:
在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的res文件。相應代碼如下:
<resources> <bool name='small_screen'>false</bool></resources>
在大屏幕設備上ActionBar就置為可見狀態。
我們并不一定需要將 bools.xml 文件放入 values-sw400dp 文件夾中, 因為Android操作系統會自動按相應路徑搜索. 例如一個設備寬 600dp (600/160=3.75 英寸) 操作系統會在values-sw600dp 和其對應文件夾中搜索 bools.xml 文件, 若沒有找到則搜索 values-sw400dp 文件夾,再沒找到就搜索 values-sw360dp 文件夾,以此類推。
3、160dp = 1英寸。320 dp = 2英寸。dp = dip。
4、你可以用這些目錄結構技巧來應付所有資源類型。
比如xml布局用指定的大小來解決,例如layout-sw360dp目錄可以適配目標寬是360dp的機型,如果還需要支持橫豎屏的話可以采用以下目錄:
layout-sw360dp-landlayout-sw360dp-port
等等,如果你有一半的用戶是阿拉伯的,那就將布局文件改為下面這樣:
layout-sw360dp-landlayout-sw360dp-portlayout-sw360dp-land-arlayout-sw360dp-port-ar
前兩個文件夾的布局可以適用于所有語言,后兩個的-ar表示阿拉伯語。
5、res資源命名規則:
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,因為我更喜歡在布局文件里設置值,在每一個xml布局文件里我通常喜歡這么做:
<ImageView android:layout_centerHorizontal='true' android:layout_marginTop='@dimen/small_margin' android:layout_width='@dimen/dashBoardWidth' android:layout_height='@dimen/dashBoardHeight' android: />
small_margin的值是在dimen.xml文件里面定義的:
<resources> <dimen name='small_margin'>4dp</dimen></resources>
這個4dp變量寫在所有dimen文件里。我有一個Excel文件,里面創建了所有不同尺寸的定義。也許你會有個疑問:為什么不讓Android操作系統來處理這些屏幕適配的問題?為什么不用一個values目錄和一個layout目錄來代替所有寫死的值呢?那當然是可以的,如果設置得當,都會得到所有的尺寸,但是對于有些元素并沒有那么容易就能得到尺寸。
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、盡量避免使用位圖(bitmap)(jpg、png)。
對于一些圖標來說,位圖是個不錯的選擇,因為它們使用簡單。但是如果可以避免使用位圖,你可以節省很多空間,采用不同的方法也可以達到很好的結果。
11、用XML進行繪圖。
位圖都可以用XML繪圖來代替的,雖然XML繪圖不是萬能的,但是它的方便性還是使我感到震驚,在Android開發文檔中有詳細的介紹,下面舉個簡單例子:
<shapexmlns: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是沒有壞處的(icon圖標例外)。
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 > <clipandroid:clipOrientation='vertical'android:drawable='@drawable/icon_magnitude_max'android:gravity='top' /></item> </layer-list>
在java程序中進行引用,用于控制光的強度。
14、為什么要用9-patch(當你可以用xml、drawables的時候)?
Android具有使用.9文件來定義drawables的選擇,有些教程闡述了怎樣用它們來做一個按鈕,這樣可以在拉伸的時候保持幾個邊角的大小不變 (并且避免了像素處理)。如果你已經知道怎樣使用.9,可能是從Web設計中學會的,那么它們或許值得一用。如果你對9-patches并不熟悉,建議你保持原樣。如果你想適應一些諸如圓角或者顏色,這就像回到了圖像編輯器的時代。許多用.9實現的效果也可以通過XML實現。
15、通過重寫onDraw()方法實現自定義控件。
有些事情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等等),默認的Button和其他UI組件會跟谷歌原生系統里的看起來差別很大。我希望這不是真的,但事實卻是如此。
20、自定義UI控件。
為了保證你的app在所有的設備里看起來是一樣的效果,你將需要自定義所有的東西。這其實沒有你想象中那么難,只要你做到了,你將能更加好地把握你的app的展示外觀。
21、Selectors是創建Button的利器。
我們在上面提到了如何在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開源組件都是API向下兼容的精心杰作。更讓人欣慰的是,ABS 擁有強大的功能用來定義ActionBar。
把響應速度作為目標
23、在運行慢的手機上測試。
?
你將在運行慢的手機上發現很多問題,即使它讓你抓狂,因為沒人會喜歡運行慢的程序。
24、盡量減少XML布局層次。
更多的層次意味著系統將為解析你的代碼付出更多的工作,這將會讓圖像渲染的更慢。
25、用Android Lint檢查程序。
在工程目錄上右鍵選擇Eclipse>Android Tools>Run Lint。它將會得到應用的一些相關信息,并能提高程序的運行速度,或者它能讓你得代碼更加清爽。
26、Android Lint可以得到錯誤信息。
它可以給你的代碼提供很詳細的信息,并在你出錯之前就可以給做出提示。
27、用可以幫助你減少視圖層次結構。
這是一種簡單的方式來去除多余的層次。好的文章都對此有所解釋,而且在 Android Developer中它也顯得與眾不同。
28、用HierarchyViewer可以直觀的看到你布局的層次。
這個智能的工具可以顯示布局中有多少層次,而且可以提示出那些可以讓程序變慢。
29、如果可以盡量用RelativeLayout。
AbsoluteLayout已經過期了,就不要用了。你經常會遇到在RelativeLayout和LinearLayout中做出選擇的情況,那就直接用RelativeLayouot吧,因為它可以讓你減少視圖層次。比如,你想實現一個如下視圖:
A Box 在屏幕左半邊 | B Box在屏幕右半邊
你首先會想到這么做:
<LinearLayoutandroid:layout_width='match_parent'android:layout_height='wrap_content'android:orientation='horizontal'><TextView android:layout_width='0dip' android:layout_height='wrap_content' android:layout_weight='1' android:text='Box A takes up left half of the screen' /><TextView android:layout_width='0dip' android:layout_height='wrap_content' android:layout_weight='1' android:text='Box B takes up left half of the screen' /> </LinearLayout>
代碼沒問題,其實你也可以這么做:
<RelativeLayoutandroid:layout_width='match_parent'android:layout_height='wrap_content'android:orientation='horizontal'><TextView android:layout_width='match_parent' android:layout_height='wrap_content' android:layout_toLeftOf='@+id/dummy_center' android:text='Box A takes up left half of the screen' /><View android:id='@+id/dummy_center' android:layout_width='0dip' android:layout_height='0dip' android:layout_gravity='center' /><TextView android:layout_width='match_parent' android:layout_height='wrap_content' android:layout_toRightOf='@+id/dummy_center' android:text='Box B takes up left half of the screen' /> </RelativeLayout>
第二個表單比第一個難看的多,事實上是相當的糟糕:我們已經介紹過一個完整的新元素了。但是假如我們要給每個Box里加入一個圖片,一般的我們將這樣做:
A Box在屏幕左半邊 圖片 | B Box在屏幕右半邊 圖片
用第一中方法,你得創建一個有兩個層次的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)
目標Bug
35、在Android控制臺里檢查所有被自動檢測出來的bug。
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/
相關文章:
