Android開發最佳實踐

Android開發最佳實踐

 

摘要

●使用 Gradle 和它推薦的工程結構

●把密碼和敏感數據放在gradle.properties

●不要自己寫 HTTP 客戶端,使用Volley或OkHttp庫

●使用Jackson庫解析JSON數據

●避免使用Guava同時使用一些類庫來避免65k method limit(一個Android程序中最多能執行65536個方法)

●使用 Fragments來呈現UI視圖

●使用 Activities 隻是為瞭管理 Fragments

●Layout 佈局是 XMLs代碼,組織好它們

●在layoutout XMLs佈局時,使用styles文件來避免使用重復的屬性

●使用多個style文件來避免單一的一個大style文件

●保持你的colors.xml 簡短DRY(不要重復自己),隻是定義調色板

●總是使用dimens.xml DRY(不要重復自己),定義通用常數

●不要做一個深層次的ViewGroup

●在使用WebViews時避免在客戶端做處理,當心內存泄露

●使用Robolectric單元測試,Robotium 做UI測試

●使用Genymotion 作為你的模擬器

●總是使用ProGuard 和 DexGuard混淆來項目

 

原文:https://tieba.yunxunmi.com/tieba-android-kz-ade479ee155e68a12bc07ccbda48303f.html

 

雲貼吧 https://tieba.yunxunmi.com/
雲搜 https://so.yunxunmi.com/ 讓搜索更簡單 采用html5完全支持手機和PC

Android SDK

將你的Android SDK放在你的home目錄或其他應用程序無關的位置。 當安裝有些包含SDK的IDE的時候,可能會將SDK放在IDE同一目錄下,當你需要升級(或重新安裝)IDE或更換的IDE時,會非常麻煩。 此外,若果你的IDE是在普通用戶,不是在root下運行,還要避免吧SDK放到一下需要sudo權限的系統級別目錄下。

 

構建系統

你的默認編譯環境應該是Gradle. Ant 有很多限制,也很冗餘。使用Gradle,完成以下工作很方便:

 

●構建APP不同版本的變種

●制作簡單類似腳本的任務

●管理和下載依賴

●自定義秘鑰

●更多

雲貼吧 https://tieba.yunxunmi.com/

同時,Android Gradle插件作為新標準的構建系統正在被Google積極的開發。

 

工程結構

有兩種流行的結構:老的Ant & Eclipse ADT 工程結構,和新的Gradle & Android Studio 工程結構, 你應該選擇新的工程結構,如果你的工程還在使用老的結構,考慮放棄吧,將工程移植到新的結構。

 

老的結構:

old-structure

├─ assets

├─ libs

├─ res

├─ src

│ └─ com/futurice/project

├─ AndroidManifest.xml

├─ build.gradle

├─ project.properties

└─ proguard-rules.pro

新的結構

new-structure

├─ library-foobar

├─ app

│ ├─ libs

│ ├─ src

│ │ ├─ androidTest

│ │ │ └─ java

│ │ │ └─ com/futurice/project

│ │ └─ main

│ │ ├─ java

│ │ │ └─ com/futurice/project

│ │ ├─ res

│ │ └─ AndroidManifest.xml

│ ├─ build.gradle

│ └─ proguard-rules.pro

├─ build.gradle

└─ settings.gradle

主要的區別在於,新的結構明確的分開瞭'source sets' (main,androidTest),Gradle的一個理念。 你可以做到,例如,添加源組‘paid’和‘free’在src中,這將成為您的應用程序的付費和免費的兩種模式的源代碼。

 

你的項目引用第三方項目庫時(例如,library-foobar),擁有一個頂級包名app從第三方庫項目區分你的應用程序是非常有用的。 然後settings.gradle不斷引用這些庫項目,其中app/build.gradle可以引用。

雲貼吧 https://tieba.yunxunmi.com/

Gradle 配置

常用結構參考Google's guide on Gradle for Android

 

小任務除瞭(shell, Python, Perl, etc)這些腳本語言,你也可以使用Gradle 制作任務。 更多信息請參考Gradle's documentation。

 

密碼在做版本release時你app的 build.gradle你需要定義 signingConfigs.此時你應該避免以下內容:

 

不要做這個.這會出現在版本控制中。

signingConfigs {

release {

storeFile file("myapp.keystore")

storePassword "password123"

keyAlias "thekey"

keyPassword "password789"

}

}

而是,建立一個不加入版本控制系統的gradle.properties文件。

KEYSTORE_PASSWORD=password123

KEY_PASSWORD=password789

那個文件是gradle自動引入的,你可以在buld.gradle文件中使用,例如:

signingConfigs {

release {

try {

storeFile file("myapp.keystore")

storePassword KEYSTORE_PASSWORD

keyAlias "thekey"

keyPassword KEY_PASSWORD

}

catch (ex) {

throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")

}

}

}

使用 Maven 依賴方案代替使用導入jar包方案 如果在你的項目中你明確使用率 jar文件,那麼它們可能成為永久的版本,如2.1.1.下載jar包更新他們是很繁瑣的, 這個問題Maven很好的解決瞭,這在Android Gradle構建中也是推薦的方法。你可 以指定版本的一個范圍,如2.1.+,然後Maven會自動升級到制定的最新版本,例如:

dependencies {

compile 'com.netflix.rxjava:rxjava-core:0.19.+'

compile 'com.netflix.rxjava:rxjava-android:0.19.+'

compile 'com.fasterxml.jackson.core:jackson-databind:2.4.+'

compile 'com.fasterxml.jackson.core:jackson-core:2.4.+'

compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.+'

compile 'com.squareup.okhttp:okhttp:2.0.+'

compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.+'

}

IDEs and text editors

 

IDE集成開發環境和文本編輯器

無論使用什麼編輯器,一定要構建一個良好的工程結構 編輯器每個人都有自己的 選擇,讓你的編輯器根據工程結構和構建系統運作,那是你自己的責任。

 

當下首推Android Studio,因為他是由谷歌開發,最接近Gradle,默認使用最新的工程結構,已經到beta階段 (目前已經有release 1.0瞭),它就是為Android開發定制的。

 

你也可以使用Eclipse ADT ,但是你需要對它進行配置,因為它使用瞭舊的工程結構 和Ant作為構建系統。你甚至可以使用純文版編輯器如Vim,Sublime Text,或者Emacs。如果那樣的話,你需要使用Gardle和adb命令行。如果使用Eclipse集成Gradle 不適合你,你隻是使用命令行構建工程,或遷移到Android Studio中來吧。

 

無論你使用何種開發工具,隻要確保Gradle和新的項目結構保持雲尋覓的方式構建應用程序,避免你的編輯器配置文件加入到版本控制。例如,避免加入Ant build.xml文件。 特別如果你改變Ant的配置,不要忘記保持build.gradle是最新和起作用的。同時,善待其他開發者,不要強制改變他們的開發工具和偏好。

 

類庫

Jackson是一個將java對象轉換成JSON與JSON轉化java類的類庫。Gson 是解決這個問題的流行方案,然而我們發現Jackson更高效,因為它支持替代的方法處理JSON:流、內存樹模型,和傳統JSON-POJO數據綁定。不過,請記住, Jsonkson庫比起GSON更大,所以根據你的情況選擇,你可能選擇GSON來避免APP 65k個方法限制。其它選擇: Json-smart and Boon JSON

 

網絡請求,緩存,圖片 執行請求後端服務器,有幾種交互的解決方案,你應該考慮實現你自己的網絡客戶端。使用 Volley或Retrofit。Volley 同時提供圖片緩存類。若果你選擇使用Retrofit,那麼考慮使用Picasso 來加載圖片和緩存,同時使用OkHttp作為高效的網絡請求。Retrofit,Picasso和OkHttp都是有同一傢公司開發(註: 是由Square 公司開發),所以它們能很好的在一起運行。OkHttp 同樣可以和Volley在一起使用 Volley.

 

RxJava是函數式反應性的一個類庫,換句話說,能處理異步的事件。 這是一個強大的和有前途的模式,同時也可能會造成混淆,因為它是如此的不同。 我們建議在使用這個庫架構整個應用程序之前要謹慎考慮。 有一些項目是使用RxJava完成的,如果你需要幫助可以跟這些人取得聯系: Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen. 我們也寫瞭一些博客: [1], [2], [3], [4].

 

如若你之前有使用過Rx的經歷,開始從API響應應用它。 另外,從簡單的UI事件處理開始運用,如單擊事件或在搜索欄輸入事件。 若對你的Rx技術有信心,同時想要將它應用到你的整體架構中,那麼請在復雜的部分寫好Javadocs文檔。 請記住其他不熟悉RxJava的開發人員,可能會非常難理解整個項目。 盡你的的全力幫助他們理解你的代碼和Rx。

 

Retrolambda 是一個在Android和預JDK8平臺上的使用Lambda表達式語法的Java類庫。 它有助於保持你代碼的緊湊性和可讀性,特別當你使用如RxJava函數風格編程時。 使用它時先安裝JDK8,在Android Studio工程結構對話框中把它設置成為SDK路徑,同時設置JAVA8_HOME和JAVA7_HOME環境變量, 然後在工程根目錄下配置 build.gradle:

dependencies {

classpath 'me.tatarka:gradle-retrolambda:2.4.+'

}

同時在每個module 的build.gradle中添加

apply plugin: 'retrolambda'

 

android {

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

 

retrolambda {

jdk System.getenv("JAVA8_HOME")

oldJdk System.getenv("JAVA7_HOME")

javaVersion JavaVersion.VERSION_1_7

}

Android Studio 提供Java8 lambdas表帶是代碼提示支持。如果你對lambdas不熟悉,隻需參照以下開始學習吧:

 

●任何隻包含一個接口的方法都是"lambda friendly"同時代碼可以被折疊成更緊湊的語法

 

●如果對參數或類似有疑問,就寫一個普通的匿名內部類,然後讓Android Status為你生成一個lambda。

 

當心dex方法數限制,同時避免使用過多的類庫 Android apps,當打包成一個dex文件時,有一個65535個應用方法強硬限制[1] [2] [3]。 當你突破65k限制之後你會看到一個致命錯誤。因此,使用一個正常范圍的類庫文件,同時使用dex-method-counts 工具來決定哪些類庫可以再65k限制之下使用,特別的避免使用Guava類庫,因為它包含超過13k個方法。

 

Activities and Fragments

Fragments應該作為你實現UI界面默認選擇。你可以重復使用Fragments用戶接口來 組合成你的應用。我們強烈推薦使用Fragments而不是activity來呈現UI界面,理由如下:

 

●提供多窗格佈局解決方案 Fragments 的引入主要將手機應用延伸到平板電腦,所以在平板電腦上你可能有A、B兩個窗格,但是在手機應用上A、B可能分別充滿 整個屏幕。如果你的應用在最初就使用瞭fragments,那麼以後將你的應用適配到其他不同尺寸屏幕就會非常簡單。

 

●屏幕間數據通信 從一個Activity發送復雜數據(例如Java對象)到另外一個Activity,Android的API並沒有提供合適的方法。不過使用Fragment,你可以使用 一個activity實例作為這個activity子fragments的通信通道。即使這樣比Activity與Activity間的通信好,你也想考慮使用Event Bus架構,使用如 Otto 或者 greenrobot EventBus作為更簡潔的實現。 如果你希望避免添加另外一個類庫,RxJava同樣可以實現一個Event Bus。

 

●Fragments 一般通用的不隻有UI 你可以有一個沒有界面的fragment作為Activity提供後臺工作。 進一步你可以使用這個特性來創建一個fragment 包含改變其它fragment的邏輯 而不是把這個邏輯放在activity中。

 

●甚至ActionBar 都可以使用內部fragment來管理 你可以選擇使用一個沒有UI界面的fragment來專門管理ActionBar,或者你可以選擇使用在每個Fragment中 添加它自己的action 來作為父Activity的ActionBar.參考.

 

很不幸,我們不建議廣泛的使用嵌套的fragments,因為 有時會引起matryoshka bugs。我們隻有當它有意義(例如,在水平滑動的ViewPager在 像屏幕一樣fragment中)或者他的確是一個明智的選擇的時候才廣泛的使用fragment。

 

在一個架構級別,你的APP應該有一個頂級的activity來包含絕大部分業務相關的fragment。你也可能還有一些輔助的activity ,這些輔助的activity與主activity 通信很簡單限制在這兩種方法 Intent.setData() 或 Intent.setAction()或類似的方法。

 

Java 包結構

Android 應用程序在架構上大致是Java中的Model-View-Controller結構。 在Android 中 Fragment和Activity通常上是控制器類(https://www.informit.com/articles/article.aspx?p=2126865). 換句話說,他們是用戶接口的部分,同樣也是Views視圖的部分。

 

正是因為如此,才很難嚴格的將fragments (或者 activities) 嚴格的劃分成 控制器controlloers還是視圖 views。 最還是將它們放在自己單獨的 fragments 包中。隻要你遵循之前提到的建議,Activities 則可以放在頂級目錄下。 若果你規劃有2到3個以上的activity,那麼還是同樣新建一個activities包吧。

 

然而,這種架構可以看做是另一種形式的MVC, 包含要被解析API響應的JSON數據,來填充的POJO的models包中。 和一個views包來包含你的自定義視圖、通知、導航視圖,widgets等等。 適配器Adapter是在數據和視圖之間。然而他們通常需要通過getView()方法來導出一些視圖, 所以你可以將adapters包放在views包裡面。

 

一些控制器角色的類是應用程序級別的,同時是接近系統的。 這些類放在managers包下面。 一些繁雜的數據處理類,比如說"DateUtils",放在utils包下面。 與後端交互負責網絡處理類,放在network包下面。

 

總而言之,以最接近用戶而不是最接近後端去安排他們。

com.futurice.project

├─ network

├─ models

├─ managers

├─ utils

├─ fragments

└─ views

├─ adapters

├─ actionbar

├─ widgets

└─ notifications

資源文件 Resources

while(!game_over)
{
    for each possible move:
        count_no_of_merges_for_2-tiles and 4-tiles
    choose the move with large number of merges
}

 

●命名遵循前綴表明類型的習慣,形如type_foo_bar.xml。例如:fragment_contact_details.xml,view_primary_button.xml,activity_main.xml.

 

組織佈局文件 若果你不確定如何排版一個佈局文件,遵循一下規則可能會有幫助。

 

●每一個屬性一行,縮進4個空格

●android:id 總是作為第一個屬性

●android:layout_**** 屬性在上邊

●style 屬性在底部

●關閉標簽/>單獨起一行,有助於調整和添加新的屬性

●考慮使用Designtime attributes 設計時佈局屬性,Android Studio已經提供支持,而不是硬編碼android:text (譯者註:墻內也可以參考stormzhang的這篇博客鏈接)。

<linearlayout

</linearlayout

xmlns:android="https://schemas.android.com/apk/res/android"

xmlns:tools="https://schemas.android.com/tools"

android:layout_WIDTH1:="match_parent"

android:layout_HEIGHT1="match_parent"

android:orientation="vertical"

>

 

<textview

</textview

android:id="@+id/name"

android:layout_WIDTH1:="match_parent"

android:layout_HEIGHT1="wrap_content"

android:layout_alignParentRight="true"

android:text="@string/name"

style="@style/FancyText"

/>

 

 

 

作為一個經驗法則,android:layout_****屬性應該在 layout XML 中定義,同時其它屬性android:**** 應放在 styler XML中。此規則也有例外,不過大體工作 的很好。這個思想整體是保持layout屬性(positioning, margin, sizing) 和content屬性在佈局文件中,同時將所有的外觀細節屬性(colors, padding, font)放 在style文件中。

 

例外有以下這些:

 

●android:id 明顯應該在layout文件中

 

●layout文件中android:orientation對於一個LinearLayout佈局通常更有意義

雲貼吧 https://tieba.yunxunmi.com/

●android:text 由於是定義內容,應該放在layout文件中

 

●有時候將android:layout_WIDTH1: 和 android:layout_HEIGHT1屬性放到一個style中作為一個通用的風格中更有意義,但是默認情況下這些應該放到layout文件中。

 

使用styles 幾乎每個項目都需要適當的使用style文件,因為對於一個視圖來說有一個重復的外觀是很常見的。 在應用中對於大多數文本內容,最起碼你應該有一個通用的style文件,例如:

@dimen/font_normal

@color/basic_black

應用到TextView 中:

<textview

</textview

android:layout_WIDTH1:="wrap_content"

android:layout_HEIGHT1="wrap_content"

android:text="@string/price"

style="@style/ContentText"

/>

你或許需要為按鈕控件做同樣的事情,不要停止在那裡。將一組相關的和重復android:****的屬性放到一個通用的style中。

 

將一個大的style文件分割成多個文件 你可以有多個styles.xml 文件。Android SDK支持其它文件,styles這個文件名稱並沒有作用,起作用的是在文件 裡xml的

標簽。因此你可以有多個style文件styles.xml,style_home.xml,style_item_details.xml,styles_forms.xml。 不用於資源文件路徑需要為系統構建起的有意義,在res/values目錄下的文件可以任意命名。

雲貼吧 https://tieba.yunxunmi.com/

colors.xml是一個調色板 在你的colors.xml文件中應該隻是映射顏色的名稱一個RGBA值,而沒有其它的。不要使用它為不同的按鈕來定義RGBA值。

不要這樣做

#FFFFFF

#2A91BD

#5F5F5F

#939393

#FFFFFF

#FF9D2F

#323232

使用這種格式,你會非常容易的開始重復定義RGBA值,這使如果需要改變基本色變的很復雜。同時,這些定義是跟一些環境關聯起來的,如button或者comment, 應該放到一個按鈕風格中,而不是在color.xml文件中。

相反,這樣做:雲貼吧 https://tieba.yunxunmi.com/

#FFFFFF

#DBDBDB

#939393

#5F5F5F

#323232

#27D34D

#2A91BD

#FF9D2F

#FF432F

向應用設計者那裡要這個調色板,名稱不需要跟”green”, “blue”, 等等相同。 “brand_primary”, “brand_secondary”, “brand_negative” 這樣的名字也是完全可以接受的。 像這樣規范的顏色很容易修改或重構,會使應用一共使用瞭多少種不同的顏色變得非常清晰。 通常一個具有審美價值的UI來說,減少使用顏色的種類是非常重要的。

像對待colors.xml一樣對待dimens.xml文件 與定義顏色調色板一樣,你同時也應該定義一個空隙間隔和字體大小的“調色板”。 一個好的例子,如下所示:

22sp

18sp

15sp

12sp

40dp

24dp

14dp

10dp

4dp

60dp

40dp

32dp

佈局時在寫 margins 和 paddings 時,你應該使用spacing_****尺寸格式來佈局,而不是像對待String字符串一樣直接寫值。 這樣寫會非常有感覺,會使組織和改變風格或佈局是非常容易。

避免深層次的視圖結構 有時候為瞭擺放一個視圖,你可能嘗試添加另一個LinearLayout。你可能使用這種方法解決:

<LinearLayout

android:layout_WIDTH1:=”match_parent”

android:layout_HEIGHT1=”match_parent”

android:orientation=”vertical”

>

<RelativeLayout

>

<LinearLayout

>

<LinearLayout

>

<LinearLayout

>

即使你沒有非常明確的在一個layout佈局文件中這樣使用,如果你在Java文件中從一個view inflate(這個inflate翻譯不過去,大傢理解就行) 到其他views當中,也是可能會發生的。

可能會導致一系列的問題。你可能會遇到性能問題,因為處理起需要處理一個復雜的UI樹結構。 還可能會導致以下更嚴重的問題StackOverflowError.

因此盡量保持你的視圖tree:學習如何使用RelativeLayout, 如何 optimize 你的佈局 和如何使用 標簽.

小心關於WebViews的問題. 如果你必須顯示一個web視圖, 比如說對於一個新聞文章,避免做客戶端處理HTML的工作, 最好讓後端工程師協助,讓他返回一個 “純” HTML。 WebViews 也能導致內存泄露 當保持引他們的Activity,而不是被綁定到ApplicationContext中的時候。 當使用簡單的文字或按鈕時,避免使用WebView,這時使用TextView或Buttons更好。

測試框架

Android SDK的測試框架還處於初級階段,特別是關於UI測試方面。Android Gradle 目前實現瞭一個叫connectedAndroidTest的測試, 它使用一個JUnit 為Android提供的擴展插件 extension of JUnit with helpers for Android.可以跑你生成的JUnit測試,

雲貼吧 https://tieba.yunxunmi.com/

隻當做單元測試時使用 Robolectric ,views 不用 它是一個最求提供”不連接設備的”為瞭加速開發的測試, 非常時候做 models 和 view models 的單元測試。 然而,使用Robolectric測試時不精確的,也不完全對UI測試。 當你對有關動畫的UI元素、對話框等,測試時會有問題, 這主要是因為你是在 “在黑暗中工作”(在沒有可控的界面情況下測試)

*Robotium 使寫UI測試非常簡單。 * 對於UI測試你不需 Robotium 跑與設備連接的測試。 但它可能會對你有益,是因為它有許多來幫助類的獲得和分析視圖,控制屏幕。 測試用例看起來像這樣簡單:

solo.sendKey(Solo.MENU);

solo.clickOnText(“More”); // searches for the first occurence of “More” and clicks on it

solo.clickOnText(“Preferences”);

solo.clickOnText(“Edit File Extensions”);

Assert.assertTrue(solo.searchText(“rtf”));

模擬器

如果你全職開發Android App,那麼買一個Genymotion emulatorlicense吧。 Genymotion 模擬器運行更快的秒幀的速度,比起典型的AVD模擬器。他有演示你APP的工具,高質量的模擬網絡連接,GPS位置,等等。它同時還有理想的連接測試。 你若涉及適配使用很多不同的設備,買一個Genymotion 雲尋覓是比你買很多真設備便宜多的。

註意:Genymotion模擬器沒有裝載所有的Google服務,如Google Play Store和Maps。你也可能需 要測試Samsung指定的API,若這樣的話你還是需要購買一個真實的Samsung設備。

混淆配置

ProGuard 是一個在Android項目中廣泛使用的壓縮和混淆打包的源碼的工具。

你是否使用ProGuard取決你項目的配置,當你構建一個release版本的apk時,通常你應該配置gradle文件。

buildTypes {

debug {

minifyEnabled false

}

release {

signingConfig signingConfigs.release

minifyEnabled true

proguardFiles ‘proguard-rules.pro’

}

}

為瞭決定哪些代碼應該被保留,哪些代碼應該被混淆,你不得不指定一個或多個實體類在你的代碼中。 這些實體應該是指定的類包含main方法,applets,midlets,activities,等等。 Android framework 使用一個默認的配置文件,可以在SDK_HOME/tools/proguard/proguard-android.txt 目錄下找到。自定義的工程指定的 project-specific 混淆規則,如在my-project/app/proguard-rules.pro中定義, 會被添加到默認的配置中。

雲貼吧 https://tieba.yunxunmi.com/

關於 ProGuard 一個普遍的問題,是看應用程序是否崩潰並報ClassNotFoundException 或者 NoSuchFieldException 或類似的異常, 即使編譯是沒有警告並運行成功。 這意味著以下兩種可能:

1.ProGuard 已經移除瞭類,枚舉,方法,成員變量或註解,考慮是否是必要的。

2.ProGuard 混淆瞭類,枚舉,成員變量的名稱,但是這些名字又被拿原始名稱使用瞭,比如通過Java的反射。

檢查app/build/outputs/proguard/release/usage.txt文件看有問題的對象是否被移除瞭。 檢查app/build/outputs/proguard/release/mapping.txt 文件看有問題的對象是否被混淆瞭。

In order to prevent ProGuard from stripping away needed classes or class members, add a keep options to your proguard config: 以防 ProGuard 剝離 需要的類和類成員,添加一個 keep選項在你的 proguard 配置文件中:

-keep class com.futurice.project.MyClass { *; }

防止 ProGuard 混淆 一些類和成員,添加 keepnames:

-keepnames class com.futurice.project.MyClass { *; }

查看更多>>

原文:https://tieba.yunxunmi.com/tieba-android-kz-ade479ee155e68a12bc07ccbda48303f.html

雲貼吧 https://tieba.yunxunmi.com/
雲搜 https://so.yunxunmi.com/ 讓搜索更簡單 采用html5完全支持手機和PC

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *