Skip to content

Latest commit

 

History

History
219 lines (197 loc) · 12.9 KB

README_zh.md

File metadata and controls

219 lines (197 loc) · 12.9 KB

AndroidQualityEssentials [English Version]

通过静态代码分析和运行时的检查来提高安卓代码质量:

最好的使用方式,是在创建新项目的时候就引入这些规则,在每次check-in之前修复检查到的任何错误(作为持续集成的一个检查步骤)。否则的话,面对成百上千的错误,是需要很大的勇气和毅力去逐个修复的。『从入门到放弃』并不是解决代码质量问题的正确态度。

目录

如何使用

  1. quality目录加入你的项目。
    • 可以直接拷贝:
      • 同步项目代码,拷贝quality目录到你项目的根目录下。
      • 在项目的build.gradle开头加入下面这一行:
      apply from: '../quality/static_analysis.gradle'
      
    • 或者作为remote module加入你的项目。就像在我的项目Android-App-Architecture-MVVM-Databinding里面这样:
      • 加入remote module:
      git remote add analysis https://github.com/BrianSpace/Android-Quality-Essentials.git
      • 然后加入build.gradle
      apply from: '../analysis/quality/static_analysis.gradle'
      
  2. 加入Lint配置
android {
    ...
    lintOptions {
        // Turn off analysis progress reporting by lint
        quiet true
        // Stop the gradle build if errors are found
        abortOnError true
        // Do not ignore lint warnings
        ignoreWarnings false
        // Treat warnings as errors
        warningsAsErrors true

        // Ignore rules list
        ignore 'GoogleAppIndexingWarning' // Remove this if the app support App Indexing
    }
    ...
}
  1. build.gradle中引入LeakCanary的依赖:
 dependencies {
   ...
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
   ...
 }
  1. 在安卓应用的Application类的onCreate中加入下列代码(别忘了加入AndroidManifest.xml中):
public class AndroidQualityEssentialsApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectAll()
                    .penaltyDeath()
                    .build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectAll()
                    .penaltyDeath()   // If violations are in Android itself or 3rd-party libs, use penaltyLog.
                    .build());

            // Avoid the process dedicated to LeakCanary for heap analysis.
            if (!LeakCanary.isInAnalyzerProcess(this)) {
                LeakCanary.install(this);
            }
        }
        ...
    }
}
  1. 在命令行中运行gradlew check来进行静态代码检查。
  • 分析报告在应用了static_analysis.gradle的项目的build/reports/目录下。
  1. 运行Debug版本的应用进行运行时检查。
  2. 把check过程加入持续集成的步骤中。

常见问题的修复

允许成员变量以"m"开头

命名规则中不允许像"mMember"这样以单个小写字母为前缀的成员变量命名方式。但是如果你喜欢这种命名方式,可以把"MemberName"模块的"format"属性改成"^[a-z][a-zA-Z0-9]*$"。也可以改成"^m[A-Z][a-zA-Z0-9]*$"来强制使用以"m"为前缀的成员变量命名方式。

给变量、参数、域自动增加"final"关键字

  1. 在Android Studio中打开"Analyze"->"Run Inspection by Name..."菜单,搜索"be final",然后运行在"Java"->"Code style issues"下的以下两条规则:
    • Field may be 'final'
    • Local variable or parameter may be final
  2. 每次检查完成后,在结果面板中点击"Make final"按钮,就可以自动添加"final"关键字了。

创建工具类(Utility Class)

对于PMD规则UseUtilityClass,如果你的类只有静态成员变量和函数,会提示你创建Utility Class。你需要:

  • 把类定义为final。
  • 创建一个私有的构造函数并抛出异常,以免被实例化。 例子:
public final class FileUtil {

    private static Context appContext;

    private FileUtil() throws InstantiationException {
        throw new InstantiationException("Utility class FileUtil should not be instantiated!");
    }

    public static void init(final Context context) {
        appContext = context.getApplicationContext();
    }

    /**
     * Get available cache directory. Prefer external over internal.
     */
    @NonNull
    public static File getAvailableCacheDir() {
        final File externalCacheDir = appContext.getExternalCacheDir();
        return externalCacheDir == null ? appContext.getCacheDir() : externalCacheDir;
    }
}

PMD规则的权衡

代码检查的规则都是人们长期总结出来的最佳实践,但并不是放之四海而皆准的真理。有些规则需要根据项目的具体需求来确定是否采用:

  1. AccessorMethodGeneration 这个规则更关注性能以及减少方法数,单就我个人而言更关心信息的封装,所以我在PMD配置中排除了这个规则。如果你更关心运行的性能以及方法数(以避免Multi-dex的问题),那你就应该把这个规则包含进来。
  2. GenericsNaming 这个规则要求泛型的参数都采用单个大写字母。从可读性的角度我更喜欢更有意义的命名方式:以"T"结尾的类型命名,如ItemTypeT。如果你更喜欢看起来更简单的单字母命名,可以把这个规则从exclude中去掉。

检查详情

命名规范

命名规范定义在quality/checkstyle/naming_convention.xml文件中。

  1. Java文件:
  2. 资源文件:
    • 使用蛇形命名法(全小写,以下划线分隔)。
    • Drawables以"bg_"、"ic_"或者"img_"开头。
    • Layouts布局文件以"activity_"、"fragment_"、"view_"、"dialog_"、"item_"或"btn_"开头。
    • Values以"attrs_"、"colors_"、"dimens_"、"strings_"或"styles_"开头。

你可以根据项目的命名规范修改相关的正则表达式。 如果只想检查命名规范,可以运行gradlew checkFileNames

使用CheckStyle检查代码风格

CheckStyle被用来检查Java代码风格。代码风格定义基于Google Java Style Guide,并做了如下修改:

  • Severity: 改为"error"
  • Line length: 改为120
  • Indentation: tab大小改为4
  • MethodName: 不允许使用下划线
  • ConstantName: 全大写,允许下划线

如果只想检查代码风格,可以运行gradlew checkCodeStyle。 如果需要在检查时排除一些文件(比如来自第三方的代码),可以在static_analysis.gradle中的checkCodeStyle任务内增加exclude项目。

静态检查:Findbugs

FindBugs检查代码中可能会导致Bug的模式。检查中需要排除在外的文件定义在这儿. 如果只想进行findbugs检查,可以运行gradlew findBugs

静态检查:PMD

PMD用来检查代码中常见缺陷的工具。规则定义在quality/pmd/pmd-ruleset.xml中。规则的完整列表参见这儿. 如果只想进行PMD检查,可以运行gradlew pmdCheck

静态检查:Android Lint

Android Lint为安卓特别开发的代码检查工具。完整的检查列表参考这儿. 如果只想进行Lint检查,可以运行gradlew lint

运行时检查:StrictMode

StrictMode对发现可能会导致UI无响应操作以及资源泄露很有效。 ThreadPolicy用来检查UI线程中的磁盘、网络I/O以及耗时操作;VmPolicy则用来检查未释放的资源。 详情请参考ThreadPolicy.Builder 以及VmPolicy.Builder

使用LeakCanary发现内存泄露

LeakCanary能帮助你发现内存泄露。它有自己单独的UI用来汇报内存泄露,列出的引用链让你能很容易地找到该从哪里断开链条,修复泄露。

致谢

License

The MIT License

Copyright (c) 2017-2017 AndroidQualityEssentials project contributors

https://github.com/BrianSpace/AndroidQualityEssentials/graphs/contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.