提高代碼質(zhì)量-工具篇

注:這是一篇翻譯文章抱环,原文:How to improve quality and syntax of your Android code绊起,為了理解連貫写半,翻譯過(guò)程中我修改了一些陳述邏輯和順序吏恭,同時(shí)也加了一些自己的補(bǔ)充惠豺。

在這片文章中辽故,我將從工具使用的角度上講述如何提高 Android 代碼質(zhì)量徒仓,這些自動(dòng)化工具包括 Checksytle、Findbugs誊垢、PMD 和 Android Lint. 團(tuán)隊(duì)中代碼意識(shí)不一致掉弛,水平參差不齊,代碼風(fēng)格迥異喂走,定下的規(guī)范也是熟視無(wú)睹殃饿。這時(shí)候就需要借助工具的力量,利用工具自動(dòng)地幫助我們檢測(cè)代碼芋肠,避免代碼惡習(xí)乎芳,預(yù)防蟻穴壞堤。

0.1 Fork 這個(gè)例子工程

我強(qiáng)烈建議你fork這個(gè)例子工程帖池,所有的使用事列都會(huì)在這個(gè)demo中呈現(xiàn)奈惑,同時(shí)你可以測(cè)試你自己寫的規(guī)則。

0.2 關(guān)于 Gradle 的 Task

理解 Gradle 的 Task 是理解這篇文章的基礎(chǔ)睡汹,我強(qiáng)烈建議你多看看關(guān)于Gradle Task的文章(例如這篇還有這篇)肴甸,當(dāng)然,本文也是滿滿的例子囚巴,所以你很容易理解原在,這也是我建議你 fork 我的代碼倉(cāng)庫(kù)的原因,把工程導(dǎo)入你的 Android studio彤叉,然后你將看到熟悉的 Gradle Task 腳本晤斩。如果你還是不太理解,也不用擔(dān)心姆坚,我將最大努力的寫好注釋澳泵。

0.3 關(guān)于 這個(gè) demo 的層級(jí)結(jié)構(gòu)

Gradle 腳本可以分散在不同的文件中,我在工程中寫了三個(gè) gradle 文件:

1 Checkstyle

Check style 是一個(gè)幫助開發(fā)者維持編碼規(guī)范標(biāo)準(zhǔn)的一個(gè)工具没宾,它能自動(dòng)地檢測(cè) Java 代碼,以減少人工檢測(cè)代碼的成本沸柔。當(dāng)你啟用 Checkstyle循衰,它能解析你的代碼并能告訴你代碼中的錯(cuò)誤或者不符合定義的規(guī)范的地方。

1.1 Android Studio 插件

Checkstyle 提供了多種IDE的插件支持褐澎,Android Studio 也不例外会钝。
進(jìn)入Android Studio設(shè)置頁(yè)面,在插件欄輸入Checkstyle:

Checkstyle插件

如果你還沒(méi)安裝 Checkstyle 的插件工三,進(jìn)入下載頁(yè)下載迁酸,然后重啟 Android Studio。啟動(dòng) Android studio 后進(jìn)入 Checkstyle 的設(shè)置頁(yè)面:

Checkstyle設(shè)置

在這里我們可以設(shè)置 Checkstyle 插件掃描范圍俭正,配置文件等信息奸鬓,默認(rèn)使用的配置文件是官方提供的文件:sun_checks.xml,我們也可以根據(jù)自己項(xiàng)目的需要定義自己的配置文件掸读,配置規(guī)則可以參考官方文檔全蝶。
設(shè)置完成之后點(diǎn)擊 “Apply” 或者 “ok” 按鈕,回到代碼中寺枉,我們便可以看到 Checkstyle 給我們的提示:

Checksylte高亮提示

1.2 Gradle 方式使用Checkstyle

如果我們需要把 Checkstyle 繼承到自動(dòng)編譯服務(wù)器中抑淫,例如:jenkins,我們需要利用 Gradle Task來(lái)執(zhí)行 Checkstyle,下面這段腳本展示了在 Gradle task 的 Checkstyle 的基本配置:

task checkstyle(type: Checkstyle) {
    configFile file("${project.rootDir}/config/quality/checkstyle/checkstyle.xml") // Where my    checkstyle config is...
    configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/config/quality/checkstyle/suppressions.xml").absolutePath // Where is my suppressions file for checkstyle is...
    source 'src'
    include '**/*.java'
    exclude '**/gen/**'
    classpath = files()
}

這個(gè) task 將會(huì)根據(jù)你指定的 checkstyle.xml 和 suppressions.xml 文件來(lái)分析你的代碼姥闪。你可以在 Android Studio 中執(zhí)行這個(gè)任務(wù):

執(zhí)行完成之后始苇,checkstyle 工具將會(huì)把每一個(gè)不合法的問(wèn)題顯示在控制臺(tái)中。

2 FindBugs

FindBugs 這個(gè)名字本身已經(jīng)揭示了它的作用筐喳,“FindBugs uses static analysis to inspect Java bytecode for occurrences of bug patterns.” FindBugs 是一個(gè)工具催式,它能通過(guò)靜態(tài)分析方式掃描 Java 字節(jié)碼,發(fā)現(xiàn)其中的可能出現(xiàn) bug 的代碼避归,它能發(fā)現(xiàn)一些常規(guī)的低級(jí)的錯(cuò)誤荣月,例如一些錯(cuò)誤的邏輯操作,也能發(fā)現(xiàn)一些比較隱晦的錯(cuò)誤梳毙。
例如:

   Person person = (Person) map.get("bob");
    if (person != null) {
        person.updateAccessTime();
    }
    String name = person.getName();

最后一行代碼哺窄,可能會(huì)出現(xiàn)空指針錯(cuò)誤。
又如:

    b.replace('b', 'p');
    if(b.equals("pop")) {
        Log.d("","");
    }

b.replace('b', ‘p’);這段代碼對(duì)b不會(huì)產(chǎn)生影響,所以是無(wú)效的萌业。

2.1 Android Studio 插件

同樣坷襟,F(xiàn)Indbugs 也提供了 Android Studio 的插件支持,插件的獲取過(guò)程和 Checkstyle 一樣生年,在安裝后之后重啟 Android studio婴程。值得注意的是 Findbugs 分析的是 Java 字節(jié)碼,所以在啟用 Findbugs 之前要保證你的工程是編譯過(guò)的抱婉,在 FIndbugs 掃描之后档叔,如果發(fā)現(xiàn)問(wèn)題,會(huì)在對(duì)應(yīng)的代碼出給出提示:

findbugs提示

2.2 Gradle 腳本使用

在Gradle使用非常簡(jiǎn)單蒸绩,下面的腳本展示了如何 FindBugs:

task findbugs(type: FindBugs) {
    ignoreFailures = false
    effort = "max"
    reportLevel = "high"
    excludeFilter = new File("${project.rootDir}/config/quality/findbugs/findbugs-filter.xml")
    classes = files("${project.rootDir}/app/build/classes")
    source 'src'
    include '**/*.java'
   exclude '**/gen/**'

    reports {
       xml.enabled = false
        html.enabled = true
        xml {
       destination "$project.buildDir/reports/findbugs/findbugs.xml"
   }
    html {
        destination "$project.buildDir/reports/findbugs/findbugs.html"
    }
}

    classpath = files()
}

腳本任務(wù)和 Checkstyle 類似衙四,F(xiàn)indBugs 可以根據(jù)我們指定的范圍進(jìn)行掃描,這個(gè)范圍我們可以通過(guò)一個(gè)過(guò)濾規(guī)則文件來(lái)制定掃描結(jié)果報(bào)告支持 HTML 和 XML 兩種格式侵贵。excludeFilter 指定了過(guò)濾器配置文件届搁,reports 指定了檢測(cè)報(bào)告的文件格式和文件地址缘薛。執(zhí)行 Findbugs 的 task 非常簡(jiǎn)單窍育,和 Checkstyle 一樣。

2.3 Findbugs 使用技巧

我強(qiáng)烈建議為 Findbugs 配置一個(gè)過(guò)濾文件宴胧,因?yàn)?Android 工程和 Java 工程稍微有些不一樣漱抓,Android 工程自動(dòng)生成的 R 文件并不符合 Findbugs 的規(guī)范,需要過(guò)濾掉恕齐。另外要注意的是:Findbugs 分析的是字節(jié)碼乞娄,你需要先編譯,再進(jìn)行 Findbugs 的分析显歧。

3 PMD

這個(gè)工具比較有趣:其實(shí) PMD 真正的名字并不是 PMD 仪或。 在其官方網(wǎng)站上你會(huì)發(fā)現(xiàn)兩個(gè)非常有趣的名字:

  • Pretty Much Done
  • Project Meets Deadline

事實(shí)上 PMD 是一個(gè)非常強(qiáng)大的工具,它的作用類似 Findbugs士骤,但是它的檢測(cè)掃描是基于源碼的范删,而且 PMD 不僅僅能檢測(cè) Java 語(yǔ)言,還能檢測(cè)其他語(yǔ)言拷肌。PMD 的目標(biāo)和 Findbugsd 非常的相似到旦,都是通過(guò)定義的規(guī)則靜態(tài)分析代碼中可能出現(xiàn)的錯(cuò)誤,為什么要同時(shí)使用 PMD 和 Findbugs呢巨缘?由于 Findbugs 和 PMD 的掃描方式不一樣添忘,PMD 能發(fā)現(xiàn)的一些 Findbugs 發(fā)現(xiàn)不了的問(wèn)題,反之亦然若锁。

3.1 Android 插件中使用

插件的下載過(guò)程不再贅述搁骑,安裝完成重啟之后,到頂部菜單 Tools 欄目可以找到 QAplug 選項(xiàng),可以執(zhí)行代碼分析:

PMD代碼分析

執(zhí)行完成靶病,會(huì)在控制臺(tái)輸出結(jié)果:

PMD執(zhí)行結(jié)果

3.2 在 Gradle 腳本中使用

下面的腳本代碼展示了如何使用PMD:

task pmd(type: Pmd) {
    ruleSetFiles = files("${project.rootDir}/config/quality/pmd/pmd-ruleset.xml")
    ignoreFailures = false
    ruleSets = []

   source 'src'
   include '**/*.java'
   exclude '**/gen/**'

    reports {
        xml.enabled = false
        html.enabled = true
    xml {
        destination "$project.buildDir/reports/pmd/pmd.xml"
    }
   html {
        destination "$project.buildDir/reports/pmd/pmd.html"
       }
    }
}

配置都和 Findbus 如出一轍会通,PMD 同樣也可以輸出 HTML 和 XML 報(bào)告,例子中選中的是 HTML 格式娄周。我強(qiáng)烈建議你定義自己的 rulesets 文件(規(guī)則集合)涕侈,關(guān)于 rulesets的配置,可以參考[官方文檔](http://pmd.sourceforge.net/pmd- 5.1.1/howtomakearuleset.html)煤辨,PMD存在爭(zhēng)議的規(guī)則比 Findbugs 要多裳涛,例如對(duì)于嵌套的 “if statement” 它總是提醒你 “These nested if statements could be combined”,或者對(duì)空的 “if statement ” 總是提醒你 “Avoid empty if statements”众辨,不過(guò)端三,我覺(jué)得是否需要把嵌套 “if statement” 合并到一個(gè) “if statement” 取決于你或者你的團(tuán)隊(duì)自己來(lái)定義,我不太建議合并 “if statement ” 這樣會(huì)降低代碼可讀性鹃彻。執(zhí)行 PMD 的 task 非常簡(jiǎn)單郊闯,和 Checkstyle 一樣。

4 Android Lint

“The Android lint tool is a static code analysis tool that checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization.” 正如官網(wǎng)所說(shuō)蛛株,Android Lint 是另一個(gè)靜態(tài)代碼分析工具,專門針對(duì) Android 工程团赁。Android Lint 除了對(duì)代碼掃描,分析潛在問(wèn)題之外谨履,還能對(duì)Android的資源進(jìn)行檢測(cè)欢摄,無(wú)用的資源,錯(cuò)位的dip資源等笋粟。

4.1 Gradle 腳本使用

android {
    lintOptions {
    abortOnError true
     lintConfig file("${project.rootDir}/config/quality/lint/lint.xml")
    // if true, generate an HTML report (with issue explanations, sourcecode, etc)
    htmlReport true
    // optional path to report (default will be lint-results.html in the builddir)
    htmlOutput file("$project.buildDir/reports/lint/lint.html")
}

我建議你單獨(dú)指定一個(gè)配置文件來(lái)決定是否過(guò)濾一些規(guī)則怀挠,規(guī)則的定義可以參考最新ADT給出的規(guī)則,參考這里害捕。使用 “severity” 配置為 “ignore” 來(lái)過(guò)濾指定的規(guī)則绿淋。 執(zhí)行 Lint 和執(zhí)行 Checkstyle 的 task 一樣。執(zhí)行完成之后到結(jié)果輸出目錄中查看報(bào)告尝盼,例如下面是我(譯者)執(zhí)行自己的工程輸出的部分截圖:

5 在一個(gè)任務(wù)統(tǒng)一使用以上工具

以上介紹完了四個(gè)工具吞滞,現(xiàn)在我們來(lái)看看如何一次同時(shí)運(yùn)行四個(gè)工具?我們可以管理 gradle task 之間的依賴關(guān)系东涡,使得我們?cè)趫?zhí)行一個(gè) task 任務(wù)的同時(shí)其他 task 也能被執(zhí)行冯吓。使用 Gradle 提供的方法,我們可以把四個(gè)工具的執(zhí)行任務(wù)添加為 “check” task 的依賴:

check.dependsOn 'checkstyle', 'findbugs', 'pmd', 'lint'

現(xiàn)在疮跑,只要我們只想 “check” 這個(gè) task 组贺,Checkstyle、Windbags祖娘、PMD 和 Android Lint 都會(huì)自動(dòng)執(zhí)行失尖。在 commit/push/merge request 之前 執(zhí)行一下 check 任務(wù)啊奄,對(duì)我們代碼質(zhì)量的提高將是一種非常棒的方式。執(zhí)行這個(gè)任務(wù)比較簡(jiǎn)單掀潮,你可以在命令行中執(zhí)行:

    gradlew check

6 總結(jié)

正如上文所說(shuō)菇夸,在 Gradle 中使用這些工具是非常簡(jiǎn)單的。這些工具不僅能在本地使用仪吧,還能部署到我們的自動(dòng)化編譯服務(wù)器上庄新,比如 Jenkins/Hudson,自動(dòng)處理掃描我們的代碼并輸出報(bào)告薯鼠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末择诈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子出皇,更是在濱河造成了極大的恐慌羞芍,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郊艘,死亡現(xiàn)場(chǎng)離奇詭異荷科,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)纱注,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門畏浆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人奈附,你說(shuō)我怎么就攤上這事全度≈缶纾” “怎么了斥滤?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)勉盅。 經(jīng)常有香客問(wèn)我佑颇,道長(zhǎng),這世上最難降的妖魔是什么草娜? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任挑胸,我火速辦了婚禮,結(jié)果婚禮上宰闰,老公的妹妹穿的比我還像新娘茬贵。我一直安慰自己,他們只是感情好移袍,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布解藻。 她就那樣靜靜地躺著,像睡著了一般葡盗。 火紅的嫁衣襯著肌膚如雪螟左。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音胶背,去河邊找鬼巷嚣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钳吟,可吹牛的內(nèi)容都是我干的廷粒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼红且,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼评雌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起直焙,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤景东,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后奔誓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斤吐,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年厨喂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了和措。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蜕煌,死狀恐怖派阱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斜纪,我是刑警寧澤贫母,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站盒刚,受9級(jí)特大地震影響腺劣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜因块,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一橘原、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涡上,春花似錦趾断、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至耻警,卻和暖如春隔嫡,著一層夾襖步出監(jiān)牢的瞬間甸怕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工腮恩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梢杭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓秸滴,卻偏偏與公主長(zhǎng)得像武契,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子荡含,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容