Android4開發入門經典 之 第十二部分:最佳實踐【私塾線上原創】

xinqing010發表於2012-03-01

效能提升

有兩個編寫有效程式碼的基本規則:

1:不要做你不需要做的。
2:不分配沒必要分配的記憶體。
 

應該儘量避免建立多餘的物件,比如:

1:在一組輸入資料中抽取字串時,嘗試返回源資料的子串,而非建立一個副本
2:如果你有一個返回String的方法,而且你知道它的結果將會一直被追加到StringBuffer,改變你的簽名和實現,在這個函式裡面直接追加,避免建立臨時物件。
3:將多維陣列切成與之平行的一維陣列
4:一個int陣列比Integer陣列要好,一個公認的事實就是兩個平行的int陣列要比一個(int,int)物件陣列要高效很多。對於其它原始資料型別亦如是

應該儘量使用Native方法 ,比如:

當處理字串時,要毫不猶豫地使用諸如String.indexOf()、String.lastIndexOf()之類的專門方法,這些是典型的用C/C++程式碼實現的方法,它們可以輕易地比實現同樣功能的Java迴圈快10-100倍

優先使用實現類,而不是介面

對於嵌入式系統來說,通過介面的引用來呼叫一個方法要比通過一個具體型別的引用呼叫virtual方法花多2倍的時間。
但是公共API除外,好的API較少考慮效能。

優先選擇static而非virtual

如果你不必訪問一個物件的欄位,使你的方法成為static方法。它可以被更快地呼叫,因為它不需要一個虛擬方法來間接呼叫。

避免內部的Getter/Setter

在Android,虛擬方法呼叫代價是昂貴的,例項欄位查詢代價更高。沿用一般物件導向程式設計實踐在公開介面中提供gettter和setter是合理的,但在一個類中你應該直接訪問欄位 。
 
訪問物件欄位要比訪問本地變數慢得多,如下面這段: 

java程式碼:
for (int i = 0; i < this.mCount; i++) 
dumpItem(this.mItems[i]); 
應該寫成這樣: 
int count = this.mCount; 
Item[] items = this.mItems; 
for (int i = 0; i < count; i++) 
dumpItems(items[i]); 
(我們用一個顯式的"this"來表明這是一個成員變數。)
同樣的,不要在for語句中的第二個從句中呼叫方法。例如下面這段程式碼將會在每次迭代中都會執行一次getCount(),這是一個巨大的浪費,你可以將它的值cache為一個int。 
java程式碼:
for (int i = 0; i < this.getCount(); i++) 
    dumpItems(this.getItem(i)); 

快取查詢欄位 , 通常,如果你將要訪問一個例項欄位多次,一個好的習慣就是建立一個臨時變數。例如: 

java程式碼:
protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) { 
        if (isHorizontalScrollBarEnabled()) { 
            int size = mScrollBar.getSize(false); 
            if (size <= 0) { 
                size = mScrollBarSize; 
            } 
            mScrollBar.setBounds(0, height - size, width, height); 
            mScrollBar.setParams( computeHorizontalScrollRange(), 
                    computeHorizontalScrollOffset(), 
                    computeHorizontalScrollExtent(), false); 
            mScrollBar.draw(canvas); 
        } 
    } 

這是對成員欄位mScrollBar的四次分開查詢,通過將mScrollBar快取到本地變數,四次成員欄位查詢變成四次本地變數引用,這樣更為高效。 
同樣地,方法引數作為本地變數擁有相同的效能特徵。

 
宣告常量為static final,主要是針對屬性欄位,你也可以將本地變數宣告為final,然而這並無真正意義上的效能提升 。
使用增強的For迴圈語句
增強的For語句對於陣列表現良好,但對iterable物件要小心使用,因為有額外的物件建立。對於ArrayList,你最好直接遍歷它,但對於其它collections,增強的For迴圈語句將會等同於顯式的迭代用法。
避免使用Enum型別
避免使用Float型別
嵌入式處理器很少具有硬體浮點支援,所以所有的“float”和“double”操作都是在軟體上進行。某些基本的浮點操作可能會花費數微秒。
避免使用JNI

支援多種螢幕

在實際開發中,由於由於不同手機的尺寸大小,螢幕解析度可能存在差異,這會帶來很多的問題,比如:

1:圖片在不同的裝置上,大小顯示不一
2:Layout在不同的裝置上,顯示不一樣,可能變形了

一些基本的解決方法:

1:對於字型,儘量使用sp作為單位,其他的儘量使用dp或者dip
2:使用wrap_content, fill_parent, 或者 dp 來定義layout的尺寸大小
3:不同密度裝置對應影像檔案的最佳比例。
對於四種密度low-dpi, medium-dpi, high-dpi, extra high-hdpi的裝置,在指定一個相同的影像檔案時,分配給各種密度的影像檔案的尺寸應該符合以下比例:3:4:6:9. 也就是要符合密度比例(120:160:240:360)。

舉個列子,假如我們要在一個密度為160dpi的裝置上使用到一個48 * 48的影像檔案。那麼對於其它密度的裝置,我們要準備的影像檔案分別是:

low-density (120dpi) : 36×36
medium-density(160dpi): 48×48
high-density (240dpi) : 72×72
high-density (360dpi): 96×96 
4:在需要的情況下,為每種尺寸的裝置提供指定的layout檔案。
5:在需要的情況下,為每種密度的裝置提供不同的影像檔案
6:不使用absoluteLayout佈局

UI最佳實踐

這是一份來自Moto的,關於Android UI的最佳實踐,要點如下:

1:閱讀UI指導方針(UI guideline)
2:理解和設計觸控模式
3:支援多種互動模式 (如鍵盤、軌跡球、觸控式螢幕等)
4:使用通知(notifications)和視窗陰影(window shade)
5:支援應用間的互動
6:保持你的使用者界操作面快速且敏感
7:使用窗體部件和資料夾
8:運用螢幕方向的改變
9:巧用圖片
10:使用適用於多裝置的佈局

這是一份來自Android官方開發者部落格,關於Android UI的最佳實踐

不應該

1.不要照搬你在其它平臺的UI設計,應該讓使用者感覺是在真正使用一個 Android 軟體,在你的商標顯示和平臺整體觀感之間做好平衡 
2.不要過度使用模態對話方塊 
3.不要使用固定的絕對定位的佈局 
4.不要使用px單位,使用dp或者為文字使用sp 
5. 不要使用太小的字型

應該

1. 為高解析度的螢幕建立資源(縮小總比放大好) 
2. 需要點選的元素要夠大 
3. 圖示設計遵循 Android 的準則 
4. 使用適當的間距(margins, padding) 
5. 支援D-pad和trackball導航 
6. 正確管理活動(activity)堆疊 
7. 正確處理螢幕方向變化 
8. 使用主題/樣式,尺寸和顏色資源來減少多餘的值 
9.和視覺互動設計師合作!!! 

設計哲學

1. 乾淨而不過於簡單 
2. 關注內容而非修飾 
3. 儲存一致,讓使用者容易投入其中,可附加少許變化 
4. 使用雲端服務(儲存和同步使用者資料)來加強使用者體驗

優秀介面的設計準則

1. 關注使用者 
2. 顯示正確的內容 
3. 給予使用者適當的回饋 
4. 有章可循的行為模式 
5. 容忍錯誤

關注使用者

1. 瞭解你的使用者(年齡,技能,文化,對你的應用的需求,使用的裝置,何時何地如何使用裝置) 
2. ‘使用者優先’的設計心態 (使用者通常是任務導向的行為模式) 
3. 更早,更頻繁的由真實使用者來測試

顯示正確的內容 

1. 最常用的操作需要最快被使用者看到並且可用 
2. 不太常用的功能可以放到選單裡面
 

給予使用者適當的回饋

1. 互動式的UI元素最少需要反映出4種不同的狀態 (default,disabled,focused,pressed) 
2. 保證操作的結果是清晰可見的 
3. 多給予使用者進度提示,但是不要干擾他們當前的操作

有章可循的行為模式

1. 行為模式遵循使用者的期望(正確的操作活動堆疊,顯示使用者期望看到的資訊和動作) 
2. 使用合適的方式來加強功能可見性(可點選的元素就應該看起來是可以點選的) 
3. 如果使用者完成一項任務需要複雜的操作,重新思考你的設計!!!

容忍錯誤

1. 只允許有意義的操作(適當禁用一些按鈕) 
2. 儘量減少不可回退的操作 
3. 允許回退(undo)比使用確定對話方塊更好(實際上,應該儘量少用確定對話方塊,它對使用者是一種干擾)如果錯誤是可能發生的,那它就一定會發生。

設計的考量

1.螢幕的物理尺寸 
2.螢幕密度 
3. 螢幕的方向(豎向和橫向) 
4.主要的UI互動方式(觸屏還是使用D-pad/trackball) 
5.軟鍵盤還是物理鍵盤
6.瞭解不同裝置之間的相異之處是非常重要的! 
7.閱讀CDD,學習裝置可能差異的地方 
8.瞭解螢幕尺寸和密度分類
 

響應的靈敏性(Designing for Responsiveness)

應用程式響應不夠靈敏的地方包括——反映遲鈍,掛起或凍結很長時間,或者需要花費很長的時間來處理輸入。
在 Android上,如果你的應用程式有一段時間響應不夠靈敏,系統會向使用者顯示一個對話方塊,這個對話方塊稱作應用程式無響應 (ANR:Application Not Responding)對話方塊。
什麼引發了ANR:在Android裡,應用程式的響應性是由Activity Manager和Window Manager系統服務監視的。當它監測到以下情況中的一個時,Android就會針對特定的應用程式顯示ANR:
1:在5秒內沒有響應輸入的事件(例如,按鍵按下,螢幕觸控)
2:BroadcastReceiver在10秒內沒有執行完畢

如何避免ANR

執行在主執行緒裡的任何方法都儘可能少做事情。特別是,Activity應該在它的關鍵生命週期方法(如onCreate()和onResume()) 裡儘可能少的去做建立操作。潛在的耗時操作,例如網路或資料庫操作,或者高耗時的計算如改變點陣圖尺寸,應該在子執行緒裡(或者以資料庫操作為例,通過非同步請 求的方式)來完成。

增強響應靈敏性

一般來說,在應用程式裡,100到200ms是使用者能感知阻滯的時間閾值。這裡有一些額外的技巧來避免ANR,並有助於讓你的應用程式看起來有響應性。
1:如果你的應用程式為響應使用者輸入正在後臺工作的話,可以顯示工作的進度(ProgressBar和ProgressDialog對這種情況來說很有用)。
2:特別是遊戲,在子執行緒裡做移動的計算。
3:如果你的應用程式有一個耗時的初始化過程的話,考慮可以顯示一個Splash Screen或者快速顯示主畫面並非同步來填充這些資訊。在這兩種情況下,你都應該顯示正在進行的進度,以免使用者認為應用程式被凍結了。
簡介:即使你的應用程式是快速且響應靈敏 的,但一些設計仍然會給使用者造成問題——與其它應用程式或對話方塊未事先計劃的互動,意外的資料丟失,意料之外的阻塞等等。簡而言之,你應該竭盡全力去開發一個與系統和其它應用程式流暢互動的應用程式。

常見的流暢性問題:

1:一個應用程式的後臺處理——例如,一個Service或者BroadcastReceiver—— 彈出一個對話方塊來響應一些事件。這可能看起來沒啥大礙,然而,當你的應用程式執行在真機上時,有可能你的應用程式在沒有獲得使用者焦點時後臺處理顯示了一個對話方塊。因此,可能會出現在活躍的應用程式後方顯示了你的應用程式的對話方塊,或者從當前應用程式 奪取焦點顯示了一個對話方塊,而不管當前使用者正在做什麼(例如,正在打電話)。 種情況就應該使用Notification來處理,而不是奪取焦點和打斷使用者。
2:另一個例子是未能正確實現Activity的onPause()和其它生命週期方法而造成意外丟失了狀態或使用者資料。

流暢性設計指南

1:別丟棄資料

如果使用者在你的應用程式中正在編輯資料時,其它Activity出現了,這時,你的應用程式被殺死時可能丟失那些資料。
Android方式”是這樣做的:能接收和編輯使用者輸入的Android應用程式應該重寫onSaveInstanceState()方法,並以恰當的方式儲存它們的狀態。 對於永續性的資料應該在onPause()方法裡面儲存。

2:不要暴露原始資料

暴露原始資料,要求其它應用程式能夠理解你的資料的格式;如果你變更了格式,那麼,你將破壞那些沒有進行同步更新的應用程式。
“Android方式”是建立一個ContentProvider,以一種清晰的、深思熟慮的和可維護的API方式暴露你的資料給其它應用程式。使用ContentProvider,就好像是插入Java介面來分離和組裝兩片高耦合的程式碼。這意味著你可以修改資料的內部格式,而不用修改由ContentProvider暴露的介面,這樣,也不會影響其它應用程式。

3:不要打斷使用者

如果使用者正在執行一個應用程式(例如,Phone程式),斷定對使用者操作的目的才是安全的。這也就是為什麼必須避免建立Activity,而是直接在當前的Activity中響應使用者的輸入。
那就是說,不要在BroadcastReceiver或在後臺執行的Service中呼叫callActivity()。這麼做會中斷當前執行的應用程式,並導致使用者惱怒。也許更糟糕的是,你的Activity可能成為“按鍵強盜”,竊取了使用者要提供給前一個Activity的輸入。視乎你的應用程式所做的事情,這可能是個壞訊息。
不選擇在後臺直接建立Activity UI,取而代之的是,應該使用NotificationManager來設定Notification。它們會出現在狀態列,並且使用者可以在他空閒的時候點選它們,來檢視你的應用程式向他顯示了什麼。
(注意,如果你的Activity已經在前臺了,以上將不適用:這時,對於使用者的輸入,使用者期望的是看到下一個Activity來響應。)

4:有太多事情要做?線上程裡做

如果你的應用程式需要執行一些昂貴或耗時的計算的話,你應該儘可能地將它挪到執行緒裡。這將阻止向使用者顯示可怕的“Application Not Responding”對話方塊。

5:不要讓一個Activity超負荷

任何值得使用的應用程式都可能有幾個不同的螢幕,當設計你的應用程式的時候,把你的應用程式看作是Activity物件的集合。從長遠來看,這會使得你的程式碼更加方便維護。

6:擴充套件系統主題

當設計你的UI時,你應該儘量避免太多自己的主題。相反的,使用同一個主題。你可以重寫或擴充套件你需要的主題部分,但至少在與其它應用程式相同的UI基礎上開始。

7:設計你的UI可以應付多螢幕解析度

不同的Android裝置可能支援不同的螢幕解析度,應確保你的佈局和圖片能足夠靈活地在不同的裝置螢幕上正常顯示。

8:假設網路很慢

你應該按照最小化的網路訪問和頻寬來編寫你的程式碼。

9:不要假定觸控式螢幕或鍵盤

建立應用程式的時候,不要假定特定的鍵盤佈局——除非你真的想限定你的應用程式只執行在某些裝置上。

10:節省裝置電池

如何讓你的應用程式最小化的佔用處理器,歸根結底還是要寫高效程式碼。為了減少無線的電量消耗,確保對錯誤條件進行正確的處理,並只獲取你要的東西。

視訊配套PPT,視訊地址【 Android4開發入門經典獨家視訊課程

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26715458/viewspace-717436/,如需轉載,請註明出處,否則將追究法律責任。

相關文章