每個安卓開發初學者應該瞭解的 12 個技巧

Nilesh Singh發表於2017-10-29

一次掌握一個技巧,更好地學習安卓

距離安迪·魯賓和他的團隊著手開發一個希望顛覆傳統手機操作模式的作業系統已經過去 12 年了,這套系統有可能讓手機或者智慧機給消費者以及軟體開發人員帶來全新的體驗。之前的智慧機僅限於收發簡訊和檢視電子郵件(當然還可以打電話),給使用者和開發者帶來很大的限制。

安卓,作為打破這個枷鎖的系統,擁有非常優秀的框架設計,給大家提供的不僅僅是一組有限的功能,更多的是自由的探索。有人會說 iPhone 才是手機產業的顛覆產品,不過我們說的不是 iPhone 有多麼酷(或者多麼貴,是吧?),它還是有限制的,而這是我們從來都不希望有的。

不過,就像本大叔說的,能力越大責任越大,我們也需要更加認真對待安卓應用的設計方式。我看到很多教程都忽略了向初學者傳遞這個理念,在動手之前請先充分理解系統架構。他們只是把一堆的概念和程式碼丟給讀者,卻沒有解釋清楚相關的優缺點,它們對系統的影響,以及該用什麼不該用什麼等等。

在這篇文章裡,我們將介紹一些初學者以及中級開發人員都應該掌握的技巧,以幫助更好地理解安卓框架。後續我們還會在這個系列裡寫更多這樣的關於實用技巧的文章。我們開始吧。

1、 @+id@id 的區別

要在 Java 程式碼裡訪問一個圖形控制元件(或元件),或者是要讓它成為其他控制元件的依賴,我們需要一個唯一的值來引用它。這個唯一值用 android:id 屬性來定義,本質上就是把使用者提供的 id 附加到 @+id/ 後面,寫入到 id 資原始檔,供其他控制元件使用。一個 Toolbar 的 id 可以這樣定義,

android:id="@+id/toolbar"

然後這個 id 值就能被 findViewById(…) 識別,這個函式會在資原始檔裡查詢 id,或者直接從 R.id 路徑引用,然後返回所查詢的 View 的型別。

而另一種,@id,和 findViewById(…) 行為一樣 - 也會根據提供的 id 查詢元件,不過僅限於佈局時使用。一般用來佈置相關控制元件。

android:layout_below="@id/toolbar"

2、 使用 @string 資源為 XML 提供字串

簡單來說,就是不要在 XML 裡直接用字串。原因很簡單。當我們在 XML 裡直接使用了字串,我們一般會在其它地方再次用到同樣的字串。想像一下當我們需要在不同的地方調整同一個字串的噩夢,而如果使用字串資源就只改一個地方就夠了。另一個好處是,使用資原始檔可以提供多國語言支援,因為可以為不同的語言建立相應的字串資原始檔。

android:text="My Awesome Application"

當你直接使用字串時,你會在 Android Studio 裡收到警告,提示說應該把寫死的字串改成字串資源。可以點選這個提示,然後按下 ALT + ENTER 開啟字串編輯。你也可以直接開啟 res 目錄下的 values 目錄裡的 strings.xml 檔案,然後像下面這樣宣告一個字串資源。

<string name="app_name">My Awesome Application</string>

然後用它來替換寫死的字串,

android:text="@string/app_name"

3、 使用 @android 和 ?attr 常量

儘量使用系統預先定義的常量而不是重新宣告。舉個例子,在佈局中有幾個地方要用白色或者 #ffffff 顏色值。不要每次都直接用 #ffffff 數值,也不要自己為白色重新宣告資源,我們可以直接用這個,

@android:color/white

安卓預先定義了很多常用的顏色常量,比如白色,黑色或粉色。最經典的應用場景是透明色:

@android:color/transparent

另一個引用常量的方式是 ?attr,用來將預先定義的屬性值賦值給不同的屬性。舉個自定義 Toolbar 的例子。這個 Toolbar 需要定義寬度和高度。寬度通常可以設定為 MATCH_PARENT,但高度呢?我們大多數人都沒有注意設計指導,只是簡單地隨便設定一個看上去差不多的值。這樣做不對。不應該隨便自定義高度,而應該這樣做,

android:layout_height="?attr/actionBarSize"

?attr 的另一個應用是點選檢視時畫水波紋效果。SelectableItemBackground 是一個預定義的 drawable,任何檢視需要增加波紋效果時可以將它設為背景:

android:background="?attr/selectableItemBackground"

也可以用這個:

android:background="?attr/selectableItemBackgroundBorderless"

來顯示無邊框波紋。

4、 SP 和 DP 的區別

雖然這兩個沒有本質上的區別,但知道它們是什麼以及在什麼地方適合用哪個很重要。

SP 的意思是縮放無關畫素,一般建議用於 TextView,首先文字不會因為顯示密度不同而顯示效果不一樣,另外 TextView 的內容還需要根據使用者設定做拉伸,或者只調整字型大小。

其他需要定義尺寸和位置的地方,可以使用 DP,也就是密度無關畫素。之前說過,DP 和 SP 的性質是一樣的,只是 DP 會根據顯示密度自動拉伸,因為安卓系統會動態計算實際顯示的畫素,這樣就可以讓使用 DP 的元件在不同顯示密度的裝置上都可以擁有相同的顯示效果。

5、 Drawable 和 Mipmap 的應用

這兩個最讓人困惑的是 - drawable 和 mipmap 有多少差異?

雖然這兩個好像有同樣的用途,但它們設計目的不一樣。mipmap 是用來儲存圖示的,而 drawable 用於任何其他格式。我們可以看一下系統內部是如何使用它們的,就知道為什麼不能混用了。

你可以看到你的應用裡有幾個 mipmap 和 drawable 目錄,每一個分別代表不同的顯示解析度。當系統從 drawable 目錄讀取資源時,只會根據當前裝置的顯示密度選擇確定的目錄。然而,在讀取 mipmap 時,系統會根據需要選擇合適的目錄,而不僅限於當前顯示密度,主要是因為有些啟動器會故意顯示較大的圖示,所以系統會使用較大解析度的資源。

總之,用 mipmap 來存放圖示或標記圖片,可以在不同顯示密度的裝置上看到解析度變化,而其它根據需要顯示的圖片資源都用 drawable。

比如說,Nexus 5 的顯示解析度是 xxhdpi。當我們把圖示放到 mipmap 目錄裡時,所有 mipmap 目錄都將讀入記憶體。而如果放到 drawable 裡,只有 drawable-xxhdpi 目錄會被讀取,其他目錄都會被忽略。

6、 使用向量圖形

為了支援不同顯示密度的螢幕,將同一個資源的多個版本(大小)新增到專案裡是一個很常見的技巧。這種方式確實有用,不過它也會帶來一定的效能開支,比如更大的 apk 檔案以及額外的開發工作。為了消除這種影響,谷歌的安卓團隊釋出了新增的向量圖形。

向量圖形是用 XML 描述的 SVG(可拉伸向量圖形),是用點、直線和曲線組合以及填充顏色繪製出的圖形。正因為向量圖形是由點和線動態畫出來的,在不同顯示密度下拉伸也不會損失解析度。而向量圖形帶來的另一個好處是更容易做動畫。往一個 AnimatedVectorDrawable 檔案裡新增多個向量圖形就可以做出動畫,而不用新增多張圖片然後再分別處理。

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp" 
    android:height="24dp" 
    android:viewportWidth="24.0" 
    android:viewportHeight="24.0">

    <path android:fillColor="#69cdff" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>

</vector>

上面的向量定義可以畫出下面的圖形,

要在你的安卓專案裡新增向量圖形,可以右鍵點選你專案裡的應用模組,然後選擇 New >> Vector Assets。然後會開啟 Assets Studio,你可以有兩種方式新增向量圖形。第一種是從 Material 圖示裡選擇,另一種是選擇本地的 SVG 或 PSD 檔案。

谷歌建議與應用相關都使用 Material 圖示,來保持安卓的連貫性和統一體驗。這裡有全部圖示,記得看一下。

7、 設定邊界的開始和結束

這是人們最容易忽略的地方之一。邊界!增加邊界當然很簡單,但是如果要考慮支援很舊的平臺呢?

邊界的“開始”和“結束”分別是“左”和“右”的超集,所以如果應用的 minSdkVersion 是 17 或更低,邊界和填充的“開始”和“結束”定義是舊的“左”/“右”所需要的。在那些沒有定義“開始”和“結束”的系統上,這兩個定義可以被安全地忽略。可以像下面這樣宣告:

android:layout_marginEnd="20dp"
android:paddingStart="20dp"

8、 使用 Getter/Setter 生成工具

在建立一個容器類(只是用來簡單的存放一些變數資料)時很煩的一件事情是寫多個 getter 和 setter,複製/貼上該方法的主體再為每個變數重新命名。

幸運的是,Android Studio 有一個解決方法。可以這樣做,在類裡宣告你需要的所有變數,然後開啟 Toolbar >> Code。快捷方式是 ALT + Insert。點選 Code 會顯示 Generate,點選它會出來很多選項,裡面有 Getter 和 Setter 選項。在保持焦點在你的類頁面然後點選,就會為當前類新增所有的 getter 和 setter(有需要的話可以再去之前的視窗操作)。很爽吧。

9、 使用 Override/Implement 生成工具

這是另一個很好用的生成工具。自定義一個類然後再擴充套件很容易,但是如果要擴充套件你不熟悉的類呢。比如說 PagerAdapter,你希望用 ViewPager 來展示一些頁面,那就需要定製一個 PagerAdapter 並實現它的過載方法。但是具體有哪些方法呢?Android Studio 非常貼心地為自定義類強行新增了一個建構函式,或者可以用快捷鍵(ALT + Enter),但是父類 PagerAdapter 裡的其他(虛擬)方法需要自己手動新增,我估計大多數人都覺得煩。

要列出所有可以過載的方法,可以點選 Code >> Generate and Override methods 或者 Implement methods,根據你的需要。你還可以為你的類選擇多個方法,只要按住 Ctrl 再選擇方法,然後點選 OK。

10、 正確理解 Context

Context 有點恐怖,我估計許多初學者從沒有認真理解過 Context 類的結構 - 它是什麼,為什麼到處都要用到它。

簡單地說,它將你能從螢幕上看到的所有內容都整合在一起。所有的檢視(或者它們的擴充套件)都通過 Context 繫結到當前的環境。Context 用來管理應用層次的資源,比如說顯示密度,或者當前的關聯活動。活動、服務和應用都實現了 Context 類的介面來為其他關聯元件提供內部資源。舉個新增到 MainActivity 的 TextView 的例子。你應該注意到了,在建立一個物件的時候,TextView 的建構函式需要 Context 引數。這是為了獲取 TextView 裡定義到的資源。比如說,TextView 需要在內部用到 Roboto 字型。這樣的話,TextView 需要 Context。而且在我們將 Context(或者 this)傳遞給 TextView 的時候,也就是告訴它繫結當前活動的生命週期。

另一個 Context 的關鍵應用是初始化應用層次的操作,比如初始化一個庫。庫的生命週期和應用是不相關的,所以它需要用 getApplicationContext() 來初始化,而不是用 getContextthisgetActivity()。掌握正確使用不同 Context 型別非常重要,可以避免記憶體洩漏。另外,要用到 Context 來啟動一個活動或服務。還記得 startActivity(…) 嗎?當你需要在一個非活動類裡切換活動時,你需要一個 Context 物件來呼叫 startActivity 方法,因為它是 Context 類的方法,而不是 Activity 類。

getContext().startActivity(getContext(), SecondActivity.class);

如果你想了解更多 Context 的行為,可以看看這裡這裡。第一個是一篇關於 Context 的很好的文章,介紹了在哪些地方要用到它。而另一個是安卓關於 Context 的文件,全面介紹了所有的功能 - 方法,靜態標識以及更多。

獎勵 #1: 格式化程式碼

有人會不喜歡整齊,統一格式的程式碼嗎?好吧,幾乎我們每一個人,在寫一個超過 1000 行的類的時候,都希望我們的程式碼能有合適的結構。而且,並不僅僅大的類才需要格式化,每一個小模組類也需要讓程式碼保持可讀性。

使用 Android Studio,或者任何 JetBrains IDE,你都不需要自己手動整理你的程式碼,像增加縮排或者 = 之前的空格。就按自己希望的方式寫程式碼,在想要格式化的時候,如果是 Windows 系統可以按下 ALT + CTRL + L,Linux 系統按下 ALT + CTRL + SHIFT + L程式碼就自動格式化好了

獎勵 #2: 使用庫

物件導向程式設計的一個重要原則是增加程式碼的可重用性,或者說減少重新發明輪子的習慣。很多初學者錯誤地遵循了這個原則。這條路有兩個方向,

  • 不用任何庫,自己寫所有的程式碼。
  • 用庫來處理所有事情。

不管哪個方向走到底都是不對的。如果你徹底選擇第一個方向,你將消耗大量的資源,僅僅是為了滿足自己擁有一切的驕傲。很可能你的程式碼沒有做過替代庫那麼多的測試,從而增加模組出問題的可能。如果資源有限,不要重複發明輪子。直接用經過測試的庫,在有了明確目標以及充分的資源後,可以用自己的可靠程式碼來替換這個庫。

而徹底走向另一個方向,問題更嚴重 - 別人程式碼的可靠性。不要習慣於所有事情都依賴於別人的程式碼。在不用太多資源或者自己能掌控的情況下儘量自己寫程式碼。你不需要用庫來自定義一個 TypeFaces(字型),你可以自己寫一個。

所以要記住,在這兩個極端中間平衡一下 - 不要重新創造所有事情,也不要過分依賴外部程式碼。保持中立,根據自己的能力寫程式碼。

這篇文章最早釋出在 What’s That Lambda 上。請訪問網站閱讀更多關於 Android、Node.js、Angular.js 等等類似文章。


via: https://android.jlelse.eu/12-practices-every-android-beginner-should-know-cd43c3710027

作者:Nilesh Singh 譯者:zpl1025 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

相關文章