持续集成对于大多数的工程师应该是比较熟悉的一个概念,大部分的公司都有集成这一说法,如果不知道可以看看百度百科的定义:

持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。许多团队发现这个过程可以大大减少集成的问题,让团队能够更快的开发内聚的软件。

说白了就是你提交代码后会手动或者自动触发软件编译,并在编译出对应版本软件后对其进行自动化测试和对外发布。
目前有很多自动化集成构建工具,可能大家最熟悉的就是jinkins了,但是随着Github的兴起,更多的人更偏向于借助一个已经搭建好的自动化构建服务器,而不是自己去搭建。如果你还在为选择GitHub集成工具而苦恼,那么可以先看下如下的这篇文章:
程序员必读:七款出色的GitHub功能集成工具
我个人选择的是Travis CI,也没啥原因就是感觉合胃口。这篇文章将会对Travis CI的使用进行一个介绍:
在开始介绍之前先贴出一篇Travis CI CEO对整个的见解:
The Smallest Distributed System

至于为啥要使用Travis CI,就我个人而言就两点:

  • 满足我日常需求
  • 易用

如果你需要更为官方的理由来说服你,那么就看下下面的文章吧,其实没多大必要,每个软件都会有受众,并且都有人说好,有人说坏,简单了解下就可以了:

5 Great Reasons to Use Travis-CI

  1. 首先登入:Travis-CI 官网

  1. 点击右上角的sign in with github按钮,会进入github的登入界面:

  2. 在要触发编译的项目上打开开关:

  1. 先在项目根目录创建.travis.yml文件,在.travis.yml文件中配置Travis-CI:
    目前Travis已经支持如下编程语言的编译了:

但是这里我们只介绍用于Android项目中的.travis.yml的编写,要学习.travis.yml的编写,最高效的方法就是查看别人开源库中怎么配置,为什么要这么配置,每项配置的含义:
下面是我自己使用的比较完整的一个配置文件,每个项目根据自己的需求来对这些开关进行配置。最简单的.travis.yml 一般只需要包含language,jdk,android,components,before_script,script 即可,配置越多编译完成地越慢。

# 表示当前的项目为Android项目,Travis CI 看到这个配置后将会提供 JVM 语言所需要的编译工具比如JDKs, Ant, Gradle, Maven等.
language: android
jdk:
- oraclejdk8
#- openjdk7
#- oraclejdk7
# 配置一些环境变量
env:
global:
- ANDROID_API_LEVEL=23
- ANDROID_BUILD_TOOLS_VERSION=23.0.3
- ANDROID_ABI=armeabi-v7a
- ADB_INSTALL_TIMEOUT=8 # minutes (2 minutes by default)
- ANDROID_EMULATOR_API=23
# 编译的分支选择
branches:
only:
- master
#except:
#- xxxx

# 所需的部件
android:
components:
# 使用最新的Android SDK工具
- platform-tools
- tools
# 编译工具的版本,这个可以在Build.gradle中查看
- build-tools-$ANDROID_BUILD_TOOLS_VERSION
# 编译项目所需要的SDK 版本
- android-$ANDROID_API_LEVEL
# 额外的components
- extra
#- add-on
# 更具体的方式
#- extra-google-google_play_services
#- extra-google-m2repository
#- extra-android-m2repository
#- addon-google_apis-google-19
# 用于运行测试用例的模拟器
- sys-img-x86-android-$ANDROID_EMULATOR_API
- sys-img-armeabi-v7a-android-$ANDROID_EMULATOR_API

# 在运行脚本之前创建模拟器
# Emulator Management: Create, Start and Wait
before_script:
- chmod +x gradlew
- echo no | android create avd --force -n test -t android-$ANDROID_EMULATOR_API --abi $ANDROID_ABI
- emulator -avd test -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
# 要运行的脚本
script:
- android list target
- ./gradlew connectedAndroidTest
- ./gradlew clean assemble check

# 安装代码统计
before_install:
- pip install --user codecov
after_success:
- codecov

# 这个不知道啥用
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
cache:
directories:
- $HOME/.m2
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
# 是否邮件通知结果
notifications:
email: false

# 证书相关
#licenses:
# - android-sdk-license-.+
# - google-gdk-license-.+

  1. Travis-CI 生命周期

下面是Travis-CI的生命周期,我们可以对这些生命周期节点进行配置如上面所示:

before_install
install
before_script
script
after_success or after_failure
OPTIONAL before_deploy
OPTIONAL deploy
OPTIONAL after_deploy
after_script

之前听到反编译一直以为反编译只能获取到资源以及AndroidManifest文件,但是在有次工作中分析问题的时候涉及到第三方的Apk,和我合作的工程师居然通过反编译获取到代码,但是刚刚工作不久感到很吃惊所以回去查找了一些资料后终于掌握了反编译技术,在后面的工作中也陆陆续续用到。今天将通过这篇博客来将自己学到的分享出来:
这篇文章将只介绍Linux系统下的反编译过程,至于Window系统和Mac系统,只是工具不同而已:

反编译源码

反编译源码涉及到如下工具:
dex2jar 将apk中的classes.dex转化成jar文件
jdgui 将apk中的classes.dex转化成jar文件

  • 将apk文件后缀改为zip并解压,得到其中的classes.dex,将classes.dex复制到d2j-dex2jar.sh所在目录dex2jar-0.0.9.15文件夹。
  • 运行
    ./d2j-dex2jar.sh classes.dex
    转换结束之后将会出现如下提示:
    dex2jar classes.dex -> classes-dex2jar.jar
  • http://jd.benow.ca/ 下载jdgui

    使用jdgui打开上述生成的classes-dex2jar.jar就可以看到代码了。

反编译资源

一般apktool用于反编译提取apk资源,提取apk资源可以使用如下命令
apktool.jar d app-signed.apk
如果要将反编译完的文件重新打包成apk,只要在命令行中输入apktool.jar b ./apkunpackfolder

目前有很多的工具比如apktool等可以对代码进行反编译获得某个Apk的源码,所以我们为了防止代码被盗用,我们在释放版本前需要对代码进行混淆处理。Android SDK已经提供了混淆工具Proguard的支持。Proguard 是一个开源的混淆工具,它的作用简单得说就是通过对代码进行混淆来加大被反编译的难度,即使反编译成功也很难获取到代码的真正语义,使得代码更加的安全。混淆是不可逆的,在混淆过程中将会丢失一些不影响正常运行的信息。除了保护代码不被反编译外还可以精简编译后的程序大小。

添加到项目中

在使用Android Studio创建新的项目的时候,AS会为我们自动添加对Proguard支持,如下所示:

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

我们的sdk已经为我们提供了两个默认的配置文件proguard-android.txt和proguard-android-optimize.txt。我们可以根据这两个文件根据自己的需求进行修改。这两个文件位于[sdk path]/tools/proguard/ 目录下。
这两个有什么区别呢根据proguard-android-optimize.txt上面的注释来看proguard-android.txt是关闭了优化标志的,如果不需要优化,那么可以使用关闭优化标志的proguard-android.txt配置文件而不是proguard-android-optimize.txt。添加优化将会引入某些风险,并不是所有的优化都能在Dalvik所有版本上运行。
这个目录下还有其他目录存放的内容如下所示:

- bin :该目录下存放的是运行Proguard的脚本,分别有两种模式一种是纯粹的脚本形式proguard.sh,一种是有GUI界面的形式proguardgui.sh。
- lib : 一些主要的jar包可以使用 "java -jar ...."形式运行
- docs: 一些Progurd使用文档,如果打算深入学习Progurd可以借助这些文档。
- examples : 一些配置例子文件。

上面gradle中配置的意思是它会使用sdk提供的proguard-android.txt 以及项目app中的proguard-rules.pro文件中的配置,所以我们可以在proguard-rules.pro进行我们项目专用的混淆配置。

还需要注意的是只有在release模式下打包apk时才会自动运行ProGuard对代码进行混淆,而在debug模式下并不会调用proguard对代码进行混淆。

下面是sdk提供的proguard-android.txt的内容

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html

# 不使用大小写混合方式命令类名
-dontusemixedcaseclassnames
# 是否混淆第三方jar
-dontskipnonpubliclibraryclasses
# 混淆时是否记录日志
-verbose

# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
# 不优化输入的类文件
-dontoptimize
# 混淆时是否做预校验
-dontpreverify
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.
# 保护注解
-keepattributes *Annotation*
# 保持哪些类不被混淆
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
# 保持指定类的成员 这里是保持 View中的get set方法不被混淆
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}

# 保持Activity中onClick使用到的方法
# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}

# 保持枚举 enum 类不被混淆
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}

# 保持 Parcelable 不被混淆
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}
# 保持静态类不被混淆
-keepclassmembers class **.R$* {
public static <fields>;
}

# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontwarn android.support.**

下面是在网上找的一些配置时候常见的标签,这里放在这个地方供大家配置的时候查看:

-include {filename}               从给定的文件中读取配置参数
-basedirectory {directoryname} 指定base目录
-injars {class_path} 指定要处理的应用程序jar和目录
-outjars {class_path} 指定处理完后要输出的jar和目录的名称
-libraryjars {classpath} 指定要处理的应用程序jar和目录所需要的程序库文件
-dontskipnonpubliclibraryclasses 指定不去忽略非公共的库类。
-dontskipnonpubliclibraryclassmembers 指定不去忽略包可见的库类的成员。

保留选项
-keep {Modifier} {class_specification} 保持指定的类文件和类的成员
-keepclassmembers {modifier} {class_specification} 保持指定类的成员
-keepclasseswithmembers {class_specification} 保持指定的类和类的成员,但条件是所有指定的类和类成员是要存在.
-keepnames {class_specification} 保持指定的类和类的成员的名称
-keepclassmembernames {class_specification} 保持指定的类的成员的名称
-keepclasseswithmembernames {class_specification} 保持指定的类和类的成员的名称
-printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件

压缩
-dontshrink 不压缩输入的类文件
-printusage {filename}
-whyareyoukeeping {class_specification}

优化
-dontoptimize 不优化输入的类文件
-assumenosideeffects {class_specification} 优化时假设指定的方法,没有任何副作用
-allowaccessmodification 优化时允许访问并修改有修饰符的类和类的成员

混淆
-dontobfuscate 不混淆输入的类文件
-printmapping {filename}
-applymapping {filename} 重用映射增加混淆
-obfuscationdictionary {filename} 使用给定文件中的关键字作为要混淆方法的名称
-overloadaggressively 混淆时应用侵入式重载
-useuniqueclassmembernames 确定统一的混淆类的成员名称来增加混淆
-flattenpackagehierarchy {package_name} 重新包装所有重命名的包并放在给定的单一包中
-repackageclass {package_name} 重新包装所有重命名的类文件中放在给定的单一包中
-dontusemixedcaseclassnames 混淆时不会产生形形色色的类名
-keepattributes {attribute_name,...} 保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 设置源文件中给定的字符串常量

在混淆后会在\app\build\outputs\mapping\release目录中产生一个mapping.txt文件它列出了原始的类,方法和字段名与混淆后代码间的映射。当从release版本中收到一个bug报告时,可以用它来翻译被混淆的代码,在Bugly以及网易云捕中都会用到这个文件。

Trace View 是Android 开发环境提供的一个性能分析工具,它能够通过图形化的方式对要分析的进程进行跟踪,并且展现的粒度可以达到方法级别。

1.使用方法

使用方法有两种
一种是通过界面的形式:

  • Android Studio -> Tool -> Android -> Android Device Manger -> 打开
  • 选择一个待分析的进程,点击start Method profiling 就开始工作了。
  • 执行要分析的某个操作,最好是进行单个动作的分析。不要大范围的动作输入,以免增加分析的困难。
  • 点击stop profiling profiling 过一小段时间就可以看得到TraceView的主视图。

一种是在代码中使用:
startMethodTracing();
stopMethodTracing();
注意这种情况下需要访问到SD卡,所以需要赋予SD卡读写权限.

运行Trace View后会生成一个.trace文件。从手机中导出这个文件
运行traceview xxx.trace 就会自动打开图形界面,就可以对这个数据进行分析了。

2.界面介绍

整个TraceView的主视图分成上下两个部分
上面是你测试进程的每个线程的时间轴,每个线程占用一行,线宽度代表了执行该函数本身操作所用的时间,
下面是捕获到的每个方法执行的各个性能指标。这里包括JDK中的方法,Android SDK中的方法,native方法以及我们自己实现的方法。

这些方法的前面有一个序号,是按照Inclu CPU时间来排序的。每点击一项就会展开成两项,一个是Children一个是Parents,分别表示这个方法中的子方法,以及当前这个方法正在被哪个方法调用。

3.重要指标

在了解重要指标之前需要先弄懂两个基本概念:
Exclusive time 表示的是该方法本身基本操作,不包括子函数调用的时间
Inclusive time 表示该方法调用所用的时间,包括子方法的调用的时间。

一些重要指标的意义:
incl CPU time: 这个方法以及这个方法的子方法的总共执行时间,以及在整个Mothod Tracing Time的百分比。
excl CPU time: 这个方法的总共执行时间,减去里面子方法的执行时间。
Call + RecurCall: 这个方法的调用次数以及递归调用的次数
CPU time call: 每次执行的时间

使用CheckStyle的必要性

一个软件开发团队往往需要有一个书面代码规范,用来统一我们的编程风格,但是这种靠主观约束的行为往往不是很靠谱,有些新来的员工他们的编程风格往往还会时不时得保持旧有的编程习惯,但是在提交代码的时候Code Reviewer看着一大坨的代码,以及快要到期的问题,只能感叹一下,口头“教育”一下新人,只要不是太难入眼一般就会让过,所以最终的代码经过长时间的维护就会成为一堆难以入眼的代码。所以最好的方式是在每个开发者自己的IDE中集成一个工具能够在修改完代码后对代码进行一次检查。CheckStyle就是为了解决这个需求产生的。

CheckStyle 顾名思义就是检查代码风格的,我们可以通过在一个团队中使用同一份代码风格约束文件来规范每个成员的代码规范。
CheckStyle 可以检查如下问题:

  • Javadoc注释
  • 命名约定
  • 标题
  • Import语句
  • 体积大小
  • 空白
  • 修饰符
  • 类设计等

Android Studio中配置CheckStyle

安装CheckStyle十分简单只要在AS插件库中查找CheckStyle-IDEA点击安装,然后重启AS即可。

在刚刚介绍的时候我们提到了代码风格约束文件,这个文件需要我们自己根据自己的需求定义,但是目前有很多现有的checkstyle 文件,网上较为多的是华为的checkstyle 文件,Googlecheckstyle 文件以及Sun 公司的checkstyle 文件。我们可以基于这些checkstyle 文件修改形成我们自己的checkstyle 文件。

在AS 中添加 checkstyle文件

当重启后,打开 AndroidStudio 的设置页面 settings -> Other Settings 你会发现多了一个 Checkstyle , 点击打开,如下图。

你会看到有一个 + 按钮,点击它即可添加自己的 checkstyle 文件。
可以点击面板的左上角下拉框 Rule 来在不同的checkstyle之间进行切换。

启动CheckStyle

选中一个文件右击在弹出的菜单项中,选择Check Current File来启动。面板上还提供了整个Module,整个Project进行check的按钮这个就不做过多的介绍了。

Google Java 代码规范

为了进一步规范Android开发者的编程规范 Google 提供了一份 Java 代码规范文档下面是它的地址:
http://google-styleguide.googlecode.com/svn/trunk/javaguide.html
下面是它对应的中文翻译:
http://hawstein.com/posts/google-java-style.html

其实上面介绍的都并不是重点,CheckStyle部分的重要部分是学会编程规范,以及如何根据编程规范配置checkstyle.xml文件,以及运行checkstyle之后出错的处理。但是需要强调下编程规范这东西不能按部就班,不要照本宣科,需要灵活对待。

checkStyle配置

checkstyle 提供了很多的配置项可供用户进行配置,下面是官网中提供的配置项:

http://checkstyle.sourceforge.net/checks.html

下面列出这些几百项的check项,需要注意的是每个check项下面还有很多的property。如果展开那就更恐怖了。

AbbreviationAsWordInName 	        The Check validate abbreviations(consecutive capital letters) length in identifier name, it also allow in enforce camel case naming.
AbstractClassName Ensures that the names of abstract classes conforming to some regular expression.
AnnotationLocation Check location of annotation on language elements.
AnnotationUseStyle This check controls the style with the usage of annotations.
AnonInnerLength Checks for long anonymous inner classes.
ArrayTrailingComma Checks if array initialization contains optional trailing comma.
ArrayTypeStyle Checks the style of array type definitions.
AtclauseOrder Checks the order of at-clauses.
AvoidEscapedUnicodeCharacters Restrict using Unicode escapes.
AvoidInlineConditionals Detects inline conditionals.
AvoidNestedBlocks Finds nested blocks.
AvoidStarImport Check that finds import statements that use the * notation.
AvoidStaticImport Check that finds static imports.
BooleanExpressionComplexity Restricts nested boolean operators (&&, ||, &, | and ^) to a specified depth (default = 3).
CatchParameterName Checks that catch parameter names conform to a format specified by the format property.
ClassDataAbstractionCoupling This metric measures the number of instantiations of other classes within the given class.
ClassFanOutComplexity The number of other classes a given class relies on.
ClassTypeParameterName Checks that class type parameter names conform to a format specified by the format property.
CommentsIndentation Controls the indentation between comments and surrounding code.
ConstantName Checks that constant names conform to a format specified by the format property.
CovariantEquals Checks that if a class defines a covariant method equals, then it defines method equals(java.lang.Object).
CustomImportOrder Checks that the groups of import declarations appear in the order specified by the user.
CyclomaticComplexity Checks cyclomatic complexity against a specified limit.
DeclarationOrder Checks that the parts of a class or interface declaration appear in the order suggested by the Code Conventions for the Java Programming Language.
DefaultComesLast Check that the default is after all the cases in a switch statement.
DescendantToken Checks for restricted tokens beneath other tokens.
DesignForExtension Checks that classes are designed for inheritance.
EmptyBlock Checks for empty blocks.
EmptyCatchBlock Checks for empty catch blocks with few options to skip violation.
EmptyForInitializerPad Checks the padding of an empty for initializer; that is whether a space is required at an empty for initializer, or such spaces are forbidden.
EmptyForIteratorPad Checks the padding of an empty for iterator; that is whether a space is required at an empty for iterator, or such spaces are forbidden.
EmptyLineSeparator Checks for blank line separators.
EmptyStatement Detects empty statements (standalone ';').
EqualsAvoidNull Checks that any combination of String literals is on the left side of an equals() comparison.
EqualsHashCode Checks that classes that override equals() also override hashCode().
ExecutableStatementCount Restricts the number of executable statements to a specified limit (default = 30).
ExplicitInitialization Checks if any class or object member explicitly initialized to default for its type value (null for object references, zero for numeric types and char and false for boolean.
FallThrough Checks for fall through in switch statements Finds locations where a case contains Java code - but lacks a break, return, throw or continue statement.
FileLength Checks for long source files.
FileTabCharacter Checks to see if a file contains a tab character.
FinalClass Checks that class which has only private constructors is declared as final.
FinalLocalVariable Ensures that local variables that never get their values changed, must be declared final.
FinalParameters Check that method/constructor/catch/foreach parameters are final.
GenericWhitespace Checks that the whitespace around the Generic tokens < and > are correct to the typical convention.
Header Checks the header of the source against a fixed header file.
HiddenField Checks that a local variable or a parameter does not shadow a field that is defined in the same class.
HideUtilityClassConstructor Make sure that utility classes (classes that contain only static methods) do not have a public constructor.
IllegalCatch Catching java.lang.Exception, java.lang.Error or java.lang.RuntimeException is almost never acceptable.
IllegalImport Checks for imports from a set of illegal packages.
IllegalInstantiation Checks for illegal instantiations where a factory method is preferred.
IllegalThrows Throwing java.lang.Error or java.lang.RuntimeException is almost never acceptable.
IllegalToken Checks for illegal tokens.
IllegalTokenText Checks for illegal token text.
IllegalType Checks that particular class are never used as types in variable declarations, return values or parameters.
ImportControl Check that controls what packages can be imported in each package.
ImportOrder Ensures that groups of imports come in a specific order.
Indentation Checks correct indentation of Java Code.
InnerAssignment Checks for assignments in subexpressions, such as in String s = Integer.toString(i = 2);.
InnerTypeLast Check nested (internal) classes/interfaces are declared at the bottom of the class after all method and field declarations.
InterfaceIsType Implements Bloch, Effective Java, Item 17 - Use Interfaces only to define types.
InterfaceTypeParameterName Checks that interface type parameter names conform to a format specified by the format property.
JavadocMethod Checks the Javadoc of a method or constructor.
JavadocPackage Checks that all packages have a package documentation.
JavadocParagraph Checks Javadoc paragraphs.
JavadocStyle Custom Checkstyle Check to validate Javadoc.
JavadocTagContinuationIndentation Checks the indentation of the continuation lines in at-clauses.
JavadocType Checks the Javadoc of a type.
JavadocVariable Checks that a variable has Javadoc comment.
JavaNCSS This check calculates the Non Commenting Source Statements (NCSS) metric for Java source files and methods.
LeftCurly Checks the placement of left curly braces on types, methods and other blocks:
LineLength Checks for long lines.
LocalFinalVariableName Checks that local final variable names conform to a format specified by the format property.
LocalVariableName Checks that local, non-final variable names conform to a format specified by the format property.
MagicNumber Checks for magic numbers.
MemberName Checks that instance variable names conform to a format specified by the format property.
MethodCount Checks the number of methods declared in each type.
MethodLength Checks for long methods.
MethodName Checks that method names conform to a format specified by the format property.
MethodParamPad Checks the padding between the identifier of a method definition, constructor definition, method call, or constructor invocation; and the left parenthesis of the parameter list.
MethodTypeParameterName Checks that class type parameter names conform to a format specified by the format property.
MissingCtor Checks that classes (except abstract one) define a ctor and don't rely on the default one.
MissingDeprecated This class is used to verify that both the java.lang.Deprecated annotation is present and the @deprecated Javadoc tag is present when either is present.
MissingOverride This class is used to verify that the java.lang.Override annotation is present when the {@inheritDoc} javadoc tag is present.
MissingSwitchDefault Checks that switch statement has "default" clause.
ModifiedControlVariable Check for ensuring that for loop control variables are not modified inside the for block.
ModifierOrder Checks that the order of modifiers conforms to the suggestions in the Java Language specification, sections 8.1.1, 8.3.1 and 8.4.3.
MultipleStringLiterals Checks for multiple occurrences of the same string literal within a single file.
MultipleVariableDeclarations Checks that each variable declaration is in its own statement and on its own line.
MutableException Ensures that exceptions (defined as any class name conforming to some regular expression) are immutable.
NeedBraces Checks for braces around code blocks.
NestedForDepth Restricts nested for blocks to a specified depth (default = 1).
NestedIfDepth Restricts nested if-else blocks to a specified depth (default = 1).
NestedTryDepth Restricts nested try-catch-finally blocks to a specified depth (default = 1).
NewlineAtEndOfFile Checks that there is a newline at the end of each file.
NoClone Checks that the clone method is not overridden from the Object class.
NoFinalizer Checks that no method having zero parameters is defined using the name finalize.
NoLineWrap Checks that chosen statements are not line-wrapped.
NonEmptyAtclauseDescription Checks that the at-clause tag is followed by description .
NoWhitespaceAfter Checks that there is no whitespace after a token.
NoWhitespaceBefore Checks that there is no whitespace before a token.
NPathComplexity Checks the npath complexity against a specified limit (default = 200).
OneStatementPerLine Checks that there is only one statement per line.
OneTopLevelClass Checks that each top-level class, interfaces or enum resides in a source file of its own.
OperatorWrap Checks line wrapping for operators.
OuterTypeFilename Checks that the outer type name and the file name match.
OuterTypeNumber Checks for the number of defined types at the "outer" level.
OverloadMethodsDeclarationOrder Checks that overload methods are grouped together.
PackageAnnotation This check makes sure that all package annotations are in the package-info.java file.
PackageDeclaration Ensures there is a package declaration and (optionally) in the correct directory.
PackageName Checks that package names conform to a format specified by the format property.
ParameterAssignment Disallow assignment of parameters.
ParameterName Checks that parameter names conform to a format specified by the format property.
ParameterNumber Checks the number of parameters that a method or constructor has.
ParenPad Checks the padding of parentheses; that is whether a space is required after a left parenthesis and before a right parenthesis, or such spaces are forbidden, with the exception that it does not check for padding of the right parenthesis at an empty for iterator.
RedundantImport Checks for imports that are redundant.
RedundantModifier Checks for redundant modifiers in interface and annotation definitions, final modifier on methods of final classes, inner interface declarations that are declared as static, non public class constructors and enum constructors, nested enum definitions that are declared as static.
Regexp A check that makes sure that a specified pattern exists (or not) in the file.
RegexpHeader Checks the header of the source against a header file that contains a
RegexpMultiline Implementation of a check that looks that matches across multiple lines in any file type.
RegexpOnFilename Implementation of a check that matches based on file and/or folder path.
RegexpSingleline Implementation of a check that looks for a single line in any file type.
RegexpSinglelineJava Implementation of a check that looks for a single line in Java files.
RequireThis Checks that code doesn't rely on the "this" default.
ReturnCount Restricts return statements to a specified count (default = 2).
RightCurly Checks the placement of right curly braces.
SeparatorWrap Checks line wrapping with separators.
SimplifyBooleanExpression Checks for overly complicated boolean expressions.
SimplifyBooleanReturn Checks for overly complicated boolean return statements.
SingleLineJavadoc Checks that a JavaDoc block which can fit on a single line and doesn't contain at-clauses
SingleSpaceSeparator Checks that non-whitespace characters are separated by no more than one whitespace.
StaticVariableName Checks that static, non-final variable names conform to a format specified by the format property.
StringLiteralEquality Checks that string literals are not used with == or !=.
SummaryJavadoc Checks that Javadoc summary sentence does not contain phrases that are not recommended to use.
SuperClone Checks that an overriding clone() method invokes super.clone().
SuperFinalize Checks that an overriding finalize() method invokes super.finalize().
SuppressWarnings This check allows you to specify what warnings that
SuppressWarningsHolder This check allows for finding code that should not be reported by Checkstyle
ThrowsCount Restricts throws statements to a specified count (default = 4).
TodoComment A check for TODO comments.
TrailingComment The check to ensure that requires that comments be the only thing on a line.
Translation The TranslationCheck class helps to ensure the correct translation of code by checking property files for consistency regarding their keys.
TypecastParenPad Checks the padding of parentheses for typecasts.
TypeName Checks that type names conform to a format specified by the format property.
UncommentedMain Detects uncommented main methods.
UniqueProperties Detects duplicated keys in properties files.
UnnecessaryParentheses Checks if unnecessary parentheses are used in a statement or expression.
UnusedImports Checks for unused import statements.
UpperEll Checks that long constants are defined with an upper ell.
VariableDeclarationUsageDistance Checks the distance between declaration of variable and its first usage.
VisibilityModifier Checks visibility of class members.
WhitespaceAfter Checks that a token is followed by whitespace, with the exception that it does not check for whitespace after the semicolon of an empty for iterator.
WhitespaceAround Checks that a token is surrounded by whitespace.
WriteTag Outputs a JavaDoc tag as information.

一般我们不会自己从头到尾来编写checkstyle.xml,我们可以根据现有的配置表根据需求进行修改。因此我们要做的就是认识每个配置项,学会修改这些配置项。

一些公司的checkStyle配置文件

下面提供一些公司的checkStyle配置文件供大家参考:
Google CheckStyle 地址
Sun CheckStyle 地址

下面是网上流传较多的华为Checkstyle,我自己的checkstyle也是根据这个进行微调的,由于这个是有注释的所以转载过来给大家,也供自己以后备用:
转载自: http://blog.csdn.net/will_awoke/article/details/12705611

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<!-- Generated by RHY @will_awoke -->
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="warning"/>
<!-- Checks for Size Violations. -->
<!-- 检查文件的长度(行) default max=2000 -->
<module name="FileLength">
<property name="max" value="2500"/>
</module>

<!-- Checks that property files contain the same keys. -->
<!-- 检查**.properties配置文件 是否有相同的key
<module name="Translation">
</module>
-->
<module name="TreeWalker">
<!-- Checks for imports -->
<!-- 必须导入类的完整路径,即不能使用*导入所需的类 -->
<module name="AvoidStarImport"/>
<!-- 检查是否从非法的包中导入了类 illegalPkgs: 定义非法的包名称-->
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<!-- 检查是否导入了不必显示导入的类-->
<module name="RedundantImport"/>
<!-- 检查是否导入的包没有使用-->
<module name="UnusedImports"/>

<!-- Checks for whitespace
<module name="EmptyForIteratorPad"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
-->

<!-- 检查类和接口的javadoc 默认不检查author 和version tags
authorFormat: 检查author标签的格式
versionFormat: 检查version标签的格式
scope: 可以检查的类的范围,例如:public只能检查public修饰的类,private可以检查所有的类
excludeScope: 不能检查的类的范围,例如:public,public的类将不被检查,但访问权限小于public的类仍然会检查,其他的权限以此类推
tokens: 该属性适用的类型,例如:CLASS_DEF,INTERFACE_DEF -->
<module name="JavadocType">
<property name="authorFormat" value="\S"/>
<property name="scope" value="protected"/>
<property name="tokens" value="CLASS_DEF,INTERFACE_DEF"/>
</module>

<!-- 检查方法的javadoc的注释
scope: 可以检查的方法的范围,例如:public只能检查public修饰的方法,private可以检查所有的方法
allowMissingParamTags: 是否忽略对参数注释的检查
allowMissingThrowsTags: 是否忽略对throws注释的检查
allowMissingReturnTag: 是否忽略对return注释的检查 -->
<module name="JavadocMethod">
<property name="scope" value="private"/>
<property name="allowMissingParamTags" value="false"/>
<property name="allowMissingThrowsTags" value="false"/>
<property name="allowMissingReturnTag" value="false"/>
<property name="tokens" value="METHOD_DEF"/>
<property name="allowUndeclaredRTE" value="true"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
<!--允许get set 方法没有注释-->
<property name="allowMissingPropertyJavadoc" value="true"/>
</module>

<!-- 检查类变量的注释
scope: 检查变量的范围,例如:public只能检查public修饰的变量,private可以检查所有的变量 -->
<module name="JavadocVariable">
<property name="scope" value="private"/>
</module>

<!--option: 定义左大括号'{'显示位置,eol在同一行显示,nl在下一行显示
maxLineLength: 大括号'{'所在行行最多容纳的字符数
tokens: 该属性适用的类型,例:CLASS_DEF,INTERFACE_DEF,METHOD_DEF,CTOR_DEF -->
<module name="LeftCurly">
<property name="option" value="nl"/>
</module>

<!-- NeedBraces 检查是否应该使用括号的地方没有加括号
tokens: 定义检查的类型 -->
<module name="NeedBraces"/>

<!-- Checks the placement of right curly braces ('}') for else, try, and catch tokens. The policy to verify is specified using property option.
option: 右大括号是否单独一行显示
tokens: 定义检查的类型 -->
<module name="RightCurly">
<property name="option" value="alone"/>
</module>

<!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
<module name="EqualsHashCode"/>

<!-- Checks for illegal instantiations where a factory method is preferred.
Rationale: Depending on the project, for some classes it might be preferable to create instances through factory methods rather than calling the constructor.
A simple example is the java.lang.Boolean class. In order to save memory and CPU cycles, it is preferable to use the predefined constants TRUE and FALSE. Constructor invocations should be replaced by calls to Boolean.valueOf().
Some extremely performance sensitive projects may require the use of factory methods for other classes as well, to enforce the usage of number caches or object pools. -->
<module name="IllegalInstantiation">
<property name="classes" value="java.lang.Boolean"/>
</module>

<!-- Checks for Naming Conventions. 命名规范 -->
<!-- local, final variables, including catch parameters -->
<module name="LocalFinalVariableName"/>

<!-- local, non-final variables, including catch parameters-->
<module name="LocalVariableName"/>

<!-- static, non-final fields -->
<module name="StaticVariableName">
<property name="format" value="(^[A-Z0-9_]{0,19}$)"/>
</module>

<!-- packages -->
<module name="PackageName" >
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
</module>

<!-- classes and interfaces -->
<module name="TypeName">
<property name="format" value="(^[A-Z][a-zA-Z0-9]{0,19}$)"/>
</module>

<!-- methods -->
<module name="MethodName">
<property name="format" value="(^[a-z][a-zA-Z0-9]{0,19}$)"/>
</module>

<!-- non-static fields -->
<module name="MemberName">
<property name="format" value="(^[a-z][a-z0-9][a-zA-Z0-9]{0,19}$)"/>
</module>

<!-- parameters -->
<module name="ParameterName">
<property name="format" value="(^[a-z][a-zA-Z0-9_]{0,19}$)"/>
</module>

<!-- constants (static, final fields) -->
<module name="ConstantName">
<property name="format" value="(^[A-Z0-9_]{0,19}$)"/>
</module>

<!-- 代码缩进 -->
<module name="Indentation">
</module>

<!-- Checks for redundant exceptions declared in throws clause such as duplicates, unchecked exceptions or subclasses of another declared exception.
检查是否抛出了多余的异常
<module name="RedundantThrows">
<property name="logLoadErrors" value="true"/>
<property name="suppressLoadErrors" value="true"/>
</module>
-->

<!-- Checks for overly complicated boolean expressions. Currently finds code like if (b == true), b || true, !false, etc.
检查boolean值是否冗余的地方
Rationale: Complex boolean logic makes code hard to understand and maintain. -->
<module name="SimplifyBooleanExpression"/>

<!-- Checks for overly complicated boolean return statements. For example the following code
检查是否存在过度复杂的boolean返回值
if (valid())
return false;
else
return true;
could be written as
return !valid();
The Idea for this Check has been shamelessly stolen from the equivalent PMD rule. -->
<module name="SimplifyBooleanReturn"/>

<!-- Checks that a class which has only private constructors is declared as final.只有私有构造器的类必须声明为final-->
<module name="FinalClass"/>

<!-- Make sure that utility classes (classes that contain only static methods or fields in their API) do not have a public constructor.
确保Utils类(只提供static方法和属性的类)没有public构造器。
Rationale: Instantiating utility classes does not make sense. Hence the constructors should either be private or (if you want to allow subclassing) protected. A common mistake is forgetting to hide the default constructor.
If you make the constructor protected you may want to consider the following constructor implementation technique to disallow instantiating subclasses:
public class StringUtils // not final to allow subclassing
{
protected StringUtils() {
throw new UnsupportedOperationException(); // prevents calls from subclass
}
public static int count(char c, String s) {
// ...
}
}
<module name="HideUtilityClassConstructor"/>
-->

<!-- Checks visibility of class members. Only static final members may be public; other class members must be private unless property protectedAllowed or packageAllowed is set.
检查class成员属性可见性。只有static final 修饰的成员是可以public的。其他的成员属性必需是private的,除非属性protectedAllowed或者packageAllowed设置了true.
Public members are not flagged if the name matches the public member regular expression (contains "^serialVersionUID$" by default). Note: Checkstyle 2 used to include "^f[A-Z][a-zA-Z0-9]*$" in the default pattern to allow CMP for EJB 1.1 with the default settings. With EJB 2.0 it is not longer necessary to have public access for persistent fields, hence the default has been changed.
Rationale: Enforce encapsulation. 强制封装 -->
<module name="VisibilityModifier"/>

<!-- 每一行只能定义一个变量 -->
<module name="MultipleVariableDeclarations">
</module>

<!-- Checks the style of array type definitions. Some like Java-style: public static void main(String[] args) and some like C-style: public static void main(String args[])
检查再定义数组时,采用java风格还是c风格,例如:int[] num是java风格,int num[]是c风格。默认是java风格-->
<module name="ArrayTypeStyle">
</module>

<!-- Checks that there are no "magic numbers", where a magic number is a numeric literal that is not defined as a constant. By default, -1, 0, 1, and 2 are not considered to be magic numbers.
<module name="MagicNumber">
</module>
-->

<!-- A check for TODO: comments. Actually it is a generic regular expression matcher on Java comments. To check for other patterns in Java comments, set property format.
检查是否存在TODO(待处理) TODO是javaIDE自动生成的。一般代码写完后要去掉。
-->
<module name="TodoComment"/>

<!-- Checks that long constants are defined with an upper ell. That is ' L' and not 'l'. This is in accordance to the Java Language Specification, Section 3.10.1.
检查是否在long类型是否定义了大写的L.字母小写l和数字1(一)很相似。
looks a lot like 1. -->
<module name="UpperEll"/>

<!-- Checks that switch statement has "default" clause. 检查switch语句是否有‘default’从句
Rationale: It's usually a good idea to introduce a default case in every switch statement.
Even if the developer is sure that all currently possible cases are covered, this should be expressed in the default branch,
e.g. by using an assertion. This way the code is protected aginst later changes, e.g. introduction of new types in an enumeration type. -->
<module name="MissingSwitchDefault"/>

<!--检查switch中case后是否加入了跳出语句,例如:return、break、throw、continue -->
<module name="FallThrough"/>

<!-- Checks the number of parameters of a method or constructor. max default 7个. -->
<module name="ParameterNumber">
<property name="max" value="5"/>
</module>

<!-- 每行字符数 -->
<module name="LineLength">
<property name="max" value="200"/>
</module>

<!-- Checks for long methods and constructors. max default 150行. max=300 设置长度300 -->
<module name="MethodLength">
<property name="max" value="300"/>
</module>

<!-- ModifierOrder 检查修饰符的顺序,默认是 public,protected,private,abstract,static,final,transient,volatile,synchronized,native -->
<module name="ModifierOrder">
</module>

<!-- 检查是否有多余的修饰符,例如:接口中的方法不必使用public、abstract修饰 -->
<module name="RedundantModifier">
</module>

<!--- 字符串比较必须使用 equals() -->
<module name="StringLiteralEquality">
</module>

<!-- if-else嵌套语句个数 最多4层 -->
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>

<!-- try-catch 嵌套语句个数 最多2层 -->
<module name="NestedTryDepth">
<property name="max" value="2"/>
</module>

<!-- 返回个数 -->
<module name="ReturnCount">
<property name="max" value="5"/>
<property name="format" value="^$"/>
</module>
</module>
</module>

CheckStyle 运行结果分析

CheckStyle 与FindBug以及Lint相比之下做的比较不足的是在IDE插件中没有提供每个运行结果警告的说明,在遇到问题的时候只能到上面提到的网站上查找原因,并且上述的网站访问速度很慢,但是好在一般点击到报错或者警告的地方一般都会大概知道是真么原因导致,反倒是不是很难。
但是今天突然上网的时候看到一篇别人写的博客,上面记录了较为常见的运行结果的说明,为了避免原博客这部分内容丢失所以特地将这篇博客转载过来:

大家也可以通过这个链接访问原始博客:http://blog.csdn.net/zhengqiqiqinqin/article/details/8450416

1.Missing a Javadoc comment:缺少JavaDoc注释
2.First sentence should end with a period:你的注释的第一行文字结束应该加上一个"."
3.Expected @throws tag for 'Exception':在注释中希望有@throws的说明,在方法前得注释中添加这样一行:* @throws Exception if has error(异常说明)
4.Parameter docType should be final:参数docType应该为final类型 解决方法:在参数docType前面加个final
5.Variable “ABC” must match pattern “^[a-z][a-zA-Z0-9]*$”变量“ABC”不符合命名规则“^[a-z][a-zA-Z0-9]*$”解决方法:把这个命名改成符合规则的命名 “aBC”
6.Utility classes should not have a public or default constructor. 接口中的内部类中不应该有公共的或者默认的构造方法
解决方法:在内部类中,定义一个私有的构造方法,然后内部类声明为final类型。如果前面有static,那么final还必须放在static之后
7.'{' is not preceded with whitespace.大括号后面必须空一格
8.'public' modifier out of order with the JLS suggestions. public顺序错误=
9.Method 'deleteChild' is not designed for extension - needs to be abstract, final or empty. 不是拓展或继承的方法,必须指定abstract,final或空
1Type is missing a javadoc commentClass 缺少类型说明
2“{” should be on the previous line“{” 应该位于前一行。解决方法:把“{”放到上一行去
3Methos is missing a javadoc comment 方法前面缺少javadoc注释。解决方法:添加javadoc注释 类似这样:
/**
* set default mock parameter.(方法说明)
* @param additionalParameters parameter additional(参数名称)
* @return data manager(返回值说明)
* @throws Exception if has error(异常说明)
*/
4 Expected @throws tag for “Exception”在注释中希望有@throws的说明
解决方法:在方法前得注释中添加这样一行:* @throws Exception if has error(异常说明)
5“.” Is preceeded with whitespace “.” 前面不能有空格。解决方法:把“(”前面的空格去掉
6“.” Is followed by whitespace“.” 后面不能有空格。解决方法:把“)”后面的空格去掉
7“=” is not preceeded with whitespace“=” 前面缺少空格。解决方法:在“=”前面加个空格
8“=” is not followed with whitespace“=” 后面缺少空格。解决方法:在“=”后面加个空格
9“}” should be on the same line“}” 应该与下条语句位于同一行。解决方法:把“}”放到下一行的前面
10Unused @param tag for “unused”没有参数“unused”,不需注释
解决方法:“* @param unused parameter additional(参数名称)” 把这行unused参数的注释去掉“
11Variable “CA” missing javadoc变量“CA”缺少javadoc注释
解决方法:在“CA“变量前添加javadoc注释:/** CA. */(注意:一定记得加上“.”)
12Line longer than 80characters行长度超过80 。解决方法:把它分成多行写。必要时候,可以ctrl+shift+f
13Line contains a tab character行含有”tab” 字符。快速解决方法:可以使用editplus中的format功能,把tab字符转化为空格,然后保存Editplus英文版安装文件在我机子上有。需要的可以来拷贝。注册Editplus,点击安装文件中注册的文件
14Redundant “Public” modifier冗余的“public” modifier 。解决方法:冗余的“public
15Final modifier out of order with the JSL suggestion Final modifier的顺序错误
16Avoid using the “.*” form of importImport格式避免使用“.*”
17Redundant import from the same package从同一个包中Import内容
18Unused import-java.util.listImport进来的java.util.list没有被使用。解决方法:去掉导入的多余的类
19Duplicate import to line 13重复Import同一个内容 解决方法:去掉导入的多余的类
20Import from illegal package从非法包中 Import内容
21while” construct must use “{}” “while” 语句缺少“{}”
22Variable “sTest1” must be private and have accessor method变量“sTest1”应该是private的,并且有调用它的方法
23Variable “ABC” must match pattern “^[a-z][a-zA-Z0-9]*$”变量“ABC”不符合命名规则“^[a-z][a-zA-Z0-9]*$”解决方法:把这个命名改成符合规则的命名 “aBC”
24“(” is followed by whitespace“(” 后面不能有空格 25“)”is proceeded by whitespace“)” 前面不能有空格
解决方法:把前面或者后面的空格去掉
25、First sentence should end with a period.解决方法:你的注释的第一行文字结束应该加上一个"."
26、Redundant throws: 'NameNotFoundException' is subclass of 'NamingException'. 'NameNotFoundException ''NamingException'的子类重复抛出异常。
解决方法:如果抛出两个异常,一个异常类是另一个的子类,那么只需要写父类
去掉NameNotFoundException异常,对应的javadoc注释异常注释说明也需要去掉
27、Parameter docType should be final. 参数docType应该为final类型 解决方法:在参数docType前面加个final
28、Line has trailing spaces. 多余的空行 解决方法:去掉这行空行
29.Must have at least one statement. 至少一个声明
解决方法:} catch (NumberFormatException nfe) {
LOG.error("Auto Renews the agreement failed", nfe);//异常捕捉里面不能为空,在异常里面加一句话。如打印等等
30'>' is not followed by whitespace.并且又有 '(' is preceded with whitespace.
定义集合和枚举的时候的时候,最后一个“>”后面要有空格,“(”前面不容许有空格。解决方法:去掉泛型
31、Got an exception - java.lang.RuntimeException: Unable to get class information for @throws tag 'SystemException'.原因:不合理的throws
解决方法:要确保某些类型,如某些类、接口不被throws。把声明的异常去掉。在实现类中抛出异常
网上参考解决方法:1、这是CheckStyle报的错。通常需要Refreh, clean/build这个Project. 如果不行,可以尝试clean all projects, restart Eclipse.
2、因为编译好的类没有在checkstyle的classpath中.所以, 只要将编译好的class配置到在<checkstyle/>的classpath中就没有这个问题了.另外, 还发现checkstyle的line length好像也有点问题, 明明没有超过120个字符, 却还是报错.无奈, 我把Eclipse中java > code style > formatter中的Maximum line with改成了100, 然后format一下, 基本就没有问题了
32、File does not end with a newline.解决方法:删掉报错的类,新建一个同名的类,把代码全部复制过去
33、Utility classes should not have a public or default constructor. 接口中的内部类中不应该有公共的或者默认的构造方法
解决方法:在内部类中,定义一个私有的构造方法,然后内部类声明为final类型。如果前面有static,那么final还必须放在static之后
34、Variable 'functionCode' must be private and have accessor methods.变量要改成private然后提供访问的方法
解决方法:给这些变量的修饰符改成private,然后提供set,get方法,并加上对应的方法javadoc注释、参数注释。并在返回值和参数类型前添加final。并把调用了这个变量的地方改成通过方法访问
35. 'X' hides a field.
public class Foo
{
private int bar;

public Foo(int bar)
{
this.bar = bar;
}
public final int getBar()
{
return bar;
}
}
全局private int bar;和局部public Foo(int bar)的bar变量名字重复。
解决方法:把方法里面的参数名称改变下就可以了public Foo(int newBar)
{
this.bar = newBar;
}。
36、Got an exception - Unexpected character 0xfffd in identifier
这是因为CheckStyle不能识别制定的编码格式。
网上参考解决方法:
1、Eclipse中可以配置,在Other-->checker中可以指定
2、可以修改checkstyle配置文件:
<module name="Checker">
<property name="severity" value="warning"/>
<property name="charset" value="UTF-8"/>
<module name="TreeWalker">
如果是UTF-8的话,就添加加粗的那条语句,就可以了。
37、 Got an exception - java.lang.RuntimeException: Unable to get class information for @throws tag *whatever*.
网上参考解决方法:选中CheckSytle的JavaDoc --> Method JavaDoc --> logLoadErrors。如果是CheckStyle自己加载时出错的,打个Log就可以了,不要整出Errors吓人。
还有一处也可能包出同样的错误。Coding Problems --> Redundant Throws --> logLoadErrors选中即可
38、Expected @param tag for 'dataManager'. 缺少dataManager参数的注释 解决方法:在注释中添加@param dataManager DataManager
网上一些其他错误的解答:
1. Parameter X should be final.
public class Foo
{
private int bar;

public Foo(int bar)
{
this.bar = bar;
}
public final int getBar()
{
return bar;
}
}
解释:public Foo(int bar)的局部变量,被认为是不可改变的,检查需要加上final关键字定义public Foo(final int bar)此错误,可以忽略不检查。

2. Redundant 'X' modifier.
public interface CacheHRTreeService extends Manager {
/**
* Organization Tree
* @param orgDto
* @return
* @throws Exception
*/
public void setOrganization(OrganizationDTO orgDto) throws Exception;
/**
* Organization Tree
* @return
* @throws Exception
*/
public OrganizationDTO getOrganization() throws Exception;
......
}
解释:多余的字段。public OrganizationDTO getOrganization() throws Exception;此时public为多余的字段,因为interface定义的时候,就是public的。需要检查。
3. - Class X should be declared as final.
解释:对于单例设计模式,要求返回唯一的类对象。但是HRFactory和ContextFactory为优化的两个类,不需求检查。
其他的单例类,依然需要进行检查。
4. - Method 'addChildrenId' is not designed for extension - needs to be
abstract, final or empty.
解释:通过父类继承的,此类有点特殊可以忽略此类。
5. Variable 'id' must be private and have accessor methods.解释:BaseHRDTO类,为父类,属性给子类继承,比较特殊。但是其他的类,声名需要加上范围'private'关键字。需要检查。
6. -Array brackets at illegal position.解释:代码写法,习惯不一样。需要检查,仅仅提示

其他较好的博客推荐:
www.blogjava.net/japper/archive/2012/05/24/379054.html

Android Lint工具是个静态代码分析工具,它可以在不运行代码和编写测试用例的情况下帮你检查项目代码中的潜在bug以及优化你的代码。

1.Lint 工具的使用:

Lint 工具结构:

要使用Lint 工具进行检测需要具备如下几个部分元素:

  • 应用源代码文件:
    包括Java文件,XML文件,图标,ProGuard配置文件。
  • lint.xml文件
    lint.xml文件是一个配置文件,用于指定你需要执行的lint检测项和自定义问题的严重等级。
  • lint 工具
    lint工具是以应用源码以及lint.xml作为输入的一个静态代码扫描工具,它可以通过命令行或者Android Studio IDE工具来启动。它主要检查代码的逻辑结构问题.一般在一个应用发布之前最好使用lint工具对项目代码进行一次检查。
  • 检查结果:
    lint的最终检查结果会显示在终端或者Android studio 的Event Log上。
运行Lint:

在Android Studio中可以为某个变异版本运行lint,或者为所有的版本运行lint。只需要在build.gradle中添加如下配置即可:

lintOptions {
// set to true to turn off analysis progress reporting by lint
quiet false
// if true, stop the gradle build if errors are found
abortOnError false
// if true, only report errors
ignoreWarnings true
}

如果要手动运行Lint 可以使用Analyze > Inspect Code.然后选择检测的范围和策略。

使用lint.xml文件配置Lint检查

我们可以在项目的根目录创建一个lint.xml文件,并在这个文件中指定lint检查选项。
lint.xml 文件包含了 父标签, 标签下面包含一个或者多个 元素. 每个 使用一个单独的属性值来指定。

<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- list of issues to configure -->
</lint>

项中我们可以禁止某个检查,或者改变某个选项的严重等级。
下面是一个例子:

<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Disable the given check in this project -->
<issue id="IconMissingDensityFolder" severity="ignore" />
<!-- Ignore the ObsoleteLayoutParam issue in the specified files -->
<issue id="ObsoleteLayoutParam">
<ignore path="res/layout/activation.xml" />
<ignore path="res/layout-xlarge/activation.xml" />
</issue>
<!-- Ignore the UselessLeaf issue in the specified file -->
<issue id="UselessLeaf">
<ignore path="res/layout/main.xml" />
</issue>
<!-- Change the severity of hardcoded strings to "error" -->
<issue id="HardcodedText" severity="error" />
</lint>
在Android Studio Setting 中配置Lint:

Lint 会对各个检测项的等级都赋予一个严重级别,我们可以在Android Studio 的 Setting中搜索Inspections选项,在这个页面上你可以对每个检查项设置一个严重等级。在修改检测项级别的时候需要认真看下description,这里描述的是每个检查选项的具体内容。

在Java代码以及XML文件中配置lint检查选项

除了使用lint.xml以及Android Studio setting对Lint检查进行设定之外,还可以在Java和XML源文件中对Lint检查进行设定。

在Java代码中对Lint进行设置:
要禁止对某个指定的Java类或者方法的Lint检查可以在Java代码中添加@SuppressLint注释。

下面的代码会忽略对onCreate方法中的NewApi这个选项的检查,但是其他方法则不会忽略这个选项的检查。

@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

下面的例子会忽略FeedProvider类的ParserError项的检查。

@SuppressLint("ParserError")
public class FeedProvider extends ContentProvider {

如果你要忽略所有项的检查可以使用如下的配置:

@SuppressLint("all")

在XML中配置lint的检查项:

我们可以使用tools:ignore 属性来禁止某个特定属性的检查,为了让这个属性被lint工具识别,必须先添加如下的名称空间:

namespace xmlns:tools="http://schemas.android.com/tools"

下面的例子展示了如何关闭 元素的UnusedResources的检查。这个选项会被它的子元素所继承,它所有的子节点都会忽略这个检查:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="UnusedResources" >
<TextView
android:text="@string/auto_update_prompt" />
</LinearLayout>

要禁止一个或者多个选项可以使用逗号来隔开。

tools:ignore="NewApi,StringFormatInvalid"

要禁止所有选项的检查可以i使用如下属性:

tools:ignore="all"

深入阅读:
https://testerhome.com/topics/3105

GitHub 地址

LeakCanary 是用于检测内存泄漏的工具,它相对与MAT十分易用。并且十分直观,它会在通知栏中给出泄漏信息,这些信息可以分享,还可以dump出来。

内存泄漏

那么什么是内存泄漏呢?在之前的内存优化的博客中已经提到过内存泄漏,这里再做下回顾:
在Java中每个对象都有自己的有限的生命周期,一超过这个生命周期就会被垃圾回收器标记回收,但是还有一种情况就是它在超过生命周期的时候它的引用还被其他对象引用,这时候它就不能被垃圾回收器正常回收,并腾出空间。就导致了内存泄漏。
总之一句话,在应该被回收的时候,却没有被回收就会导致内存泄漏。内存泄漏的结果就是有限的内存被耗尽,最终导致OOM。

那么怎么将LeakCanary呢?下面将会对其一步一步介绍:

添加依赖

dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2'
}

这里有三个依赖分别对应的是debug版本,release版本,测试版本的对应依赖,之所以分成这么多个是因为需要在每个不同的版本表现出不同的行为。

在项目中引入

创建MyApplication类,在该类中创建getRefWatcher静态方法,通过该静态方法提供LeakCanary.install(this)返回的RefWatcher对象,这个对象用于内存泄漏溢出检测。

public class MyApplication extends Application{
public static RefWatcher getRefWatcher(Context context) {
MyApplication application = (MyApplication) context
.getApplicationContext();
return application.refWatcher;
}
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);
}
}

将MyApplication设置为当前应用。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.idealist.testleakcandy" >

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".MyApplication"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

点击按钮的时候启动AsyncTask,在AsyncTask中睡眠20秒,由于AsyncTask持有外部类MainActivity的引用所以当按钮按下的时候,如果转屏就会发生内存溢出。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RefWatcher refWatcher = MyApplication.getRefWatcher(this);
refWatcher.watch(this);
mButton = (Button) findViewById(R.id.buttons);
mButton.setOnClickListener(this);
}

@Override
public void onClick(View v) {
startAsyncTask();
}

private void startAsyncTask() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(20000);
return null;
}
}.execute();
}
}

运行结果如下:

较好的博客:
http://blog.csdn.net/watermusicyes/article/details/46333925
http://www.jianshu.com/p/0049e9b344b0
http://www.tuicool.com/articles/RvURJv

相对于早期Android开发目前有很多的技术以及工具用于提高代码的质量其中就包含有静态代码分析技术,我们之前介绍过的Lint也是属于这类静态代码分析工具,它不仅能够找到Java代码层次的问题,还可帮你找到布局等XML文件中的问题,在工作中我们每次开发出一个新特性并释放版本的时候就有一个硬性的指标每个类型的Lint问题必须达到什么范围才能申请释放版本。
除了Lint我们今天将要介绍一款静态代码分析工具FindBugs,从字面意思很容易看出它的用处就是通过静态代码分析找出潜在的Bug。这个工具十分好用,我自己在开发中也在使用这个工具,并且可以减少很多因为一时疏忽倒置的bug。

官方网址

FindBugs Intellij 插件下载地址

Gradle FindBugs 插件使用说明

在Android Studio中安装FindBug:

FindBug在Android Studio中的安装方式和AS的其他插件一样就是到插件库里面搜索Findbug.点击Install,安装结束后重启一次AS即可。

安装完就会在AS的底部多出一个选项卡如下所示:

其中最左边的按钮有三大类,一类是FindBug寻找问题的范围,一类是查找完问题后显示问题的形式,这两个都可以分成文件级,类级别,包级别,模块级别,项目级别。还有一类是常用工具类以及导出结果的工具。

要启动FindBug可以通过上面面板的第一类按钮,或者通过右键弹出的菜单中找到FindBug选项。

下面是为了介绍FindBug的使用做出的一个简单的Bug。
通过FindBug就可以找到这个Bug并按照如下的形式显示出来:

Android 添加过滤

如果我们在没有进行任何过滤的情况下找到的结果可能会令人失望,它会把自动生成的代码也考虑在内。因此我们在进行Bug查找的时候首先需要添加过滤。
下面是过滤掉Android自动生成的代码的配置:

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Match>
<!-- ignore all issues in resource generation -->
<Class name="~.*\.R\$.*"/>
</Match>
<Match>
<Class name="~.*\.Manifest\$.*"/>
</Match>
</FindBugsFilter>

另一个需要过滤的可能就是你测试用例的警告,可以使用如下方式进行过滤

<!-- ignore all bugs in test classes, except for those bugs specifically relating to JUnit tests -->
<Match>
<Class name="~.*\.*Test" />
<!-- test classes are suffixed by 'Test' -->
<Not>
<Bug code="IJU" /> <!-- 'IJU' is the code for bugs related to JUnit test code -->
</Not>
</Match>

在编写完这些过滤条件就可以在Android Studio中的(File > Settings->FindBugs-IDEA. -> filter选项卡中添加,下面是对应的页面:

我们还可以自动化运行FindBug静态代码分析,只要将如下的任务写到项目的gradle.build中:

apply plugin: 'findbugs'
task findbugs(type: FindBugs) {
ignoreFailures = false
effort = "default"
reportLevel = "medium"
excludeFilter = new File("${project.rootDir}/findbugs/findbugs-filter.xml")
classes = files("${project.rootDir}/app/build/intermediates/classes")
source = fileTree('src/main/java/')
classpath = files()
reports {
xml.enabled = true
html.enabled = true
xml {
destination "$project.buildDir/findbugs/findbugs-output.xml"
}
html {
destination "$project.buildDir/findbugs/findbugs-output.html"
}
}
}

具体的配置可以查看https://gradle.org/docs/current/dsl/org.gradle.api.plugins.quality.FindBugs.html。

结果分析

在结果的展示方面FindBug和Lint做的都不错,能够做到很详细得罗列出具体的原因,一般一看就明白很清晰,实在看不明白点击下每个项,从代码中也可以推测出具体的意思,这里就不展开介绍了。

Bugly 网易云捕 Crashlytic 是目前比较流行的崩溃异常的收集工具,能够及时地跟踪我们发布出去的Apk的质量并有专门的统计功能,能够让我们运筹帷幄之中,发现Bug于千里之外。借来将介绍怎么将Bugly,网易云捕这两款产品应用到我们项目中。
在这里我们都只介绍自动导入的方式,如果要手动导入可以到官网查看对应的信息,这个没什么技术含量,一看就会,之所以在这里介绍第一是为了整个知识体系的完整性,其二是为了避免每次都查阅官网耗费时间。

在介绍网易云捕和Bugly之前先贴一个别人关于当前代码质量管理工具对比的文章以便让大家对这些工具有个初步的了解:
移动平台质量跟踪系统对比-crashlytics、网易云捕、友盟、bugly

网易云捕


官方地址
一. 库文件导入
方式一:自动导入(推荐)

在Module的build.gradle文件中添加依赖和属性配置:

android {
defaultConfig {
ndk {
//设置支持的SO库架构
abiFilters "armeabi" //,"armeabi-v7a", "x86","arm64-v8a","x86_64"
}
}
}

dependencies {
compile 'com.netease.nis.plugin:bugrpt:latest.release' //集成最新版本,也可以指定版本号,比如3.6.5
}

注意:自动集成时会自动包含Bugrpt SO库,建议在Module的build.gradle文件中使用NDK的“abiFilter”配置,设置支持的SO库架构。
如果在添加“abiFilter”之后Android Studio出现以下提示:

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.
则在项目根目录的gradle.properties文件中添加:

android.useDeprecatedNdk=true

二. 权限信息配置

需要在AndroidManifest.xml中添加以下权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/><!-- 获取设备信息 -->
<uses-permission android:name="android.permission.INTERNET"/><!-- 网络通信-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><!-- 获取网络状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><!-- 获取MAC地址-->
<uses-permission android:name="android.permission.READ_LOGS" /><!-- 获取日志-->

在Android M系统以后,android.permission.READ_PHONE_STATE被设定为敏感权限,如果AndroidManifest.xml文件中targetSdkVersion被设置为23以上,且代码中没有请求过该权限,可能导致获取的imei、deviceID等设备信息为空,但是对程序的稳定性并没有影响。

三. AppID配置
还需在AndroidManifest.xml的application中添加标签,其中android:value填写您APP的AppID值,可以在”用户中心“-”设置“-”产品信息“中获取。

<application>
<meta-data android:name="BUGRPT_APPID" android:value="Please input your Appid"/>
</application>

四. 简单的初始化调用

在项目Application类或者主Activity类的onCreate()方法中添加以下代码:

CrashHandler.init(getApplicationContext());

如果Java层或NDK代码发生异常时,bugrpt便会捕获到该异常并发送给服务器。

六. 简单例子

  • Java 例子:
protected void onCreate(Bundle savedInstanceState) {  
super.onCreate(savedInstanceState);
//1.初始化云捕sdk
com.netease.nis.bugrpt.CrashHandler.getInstance().init(this.getApplicationContext(),null);

setContentView(R.layout.activity_main);
btn_crash = (Button)findViewById(R.id.btn_crash);
btn_crash.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//2.测试异常代码
throw new RuntimeException("This is a crash!");
}
});
}
  • NDK 例子
    static {
    //导入demo.so
      System.loadLibrary("demo");
    }
    public native void msg(String s);

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //1.初始化云捕sdk
    com.netease.nis.bugrpt.CrashHandler.getInstance().init(this.getApplicationContext(),null);

    btn_crash.setOnClickListener(new OnClickListener() {
       @Override
       public void onClick(View v) {
    //2.调用ndk层msg函数
         msg("hellondk");
       }
    });
    }
    而msg函数则是打印一个字符串最后触发了一个异常,C++实现代码如下:
    JNIEXPORT void msg(JNIEnv *env, jobject  clazz, jstring str)
    {
    char *pszstr = NULL;
    pszstr = jstringTostring(env, str);
    LOGI("%s", pszstr);
    free(pszstr);
      //以下是触发异常的代码
    pszstr = NULL;
    *pszstr = 0;
    }
    可以尝试生成APK之后,点击按钮触发模拟异常,后台便能查询到如下崩溃日志:

崩溃日志内容:

--- --- --- --- NATIVE CRASH LOG BY BUGRPT- --- --- --- --- ---
CRASH TIME: 1425530709912
CRASH APP: com.example.crash, pid: 12916, tid: 12916
Build fingerprint: 'Meizu/meizu_mx3/mx3:4.4.4/KTU84P/m35x.Flyme_OS_3.7.3.20140909113158:user/release-keys'
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
registers:
r0 00000000 r1 00000000 r2 00000001 r3 00000000
r4 774a1458 r5 415ab438 r6 00000000 r7 6d460dd0
r8 beb81508 r9 6d460dc8 10 415ab448 fp beb8151c
ip 00000001 sp beb81500 lr 40047ce1 pc 7528edf2 cpsr 60070030
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
callstacks:
#00 pc 00000df2 /data/app-lib/com.example.crash-2/libdemo.so (msg + 21)
#01 pc 0001db8c /system/lib/libdvm.so (dvmPlatformInvoke + 70)
#02 pc 0004e174 /system/lib/libdvm.so (_Z16dvmCallJNIMethodPKjP6JValuePK6MethodP6Thread + 18f)
#03 pc 00026fa0 /system/lib/libdvm.so
#04 pc 0002dfb8 /system/lib/libdvm.so (_Z11dvmMterpStdP6Thread + 4c)
#05 pc 0002b61c /system/lib/libdvm.so (_Z12dvmInterpretP6ThreadPK6MethodP6JValue + b8)
#06 pc 0006087a /system/lib/libdvm.so (_Z15dvmInvokeMethodP6ObjectPK6MethodP11ArrayObjectS5_P11ClassObjectb + 189)
#07 pc 00068896 /system/lib/libdvm.so
#08 pc 00026fa0 /system/lib/libdvm.so
#09 pc 0002dfb8 /system/lib/libdvm.so (_Z11dvmMterpStdP6Thread + 4c)
#10 pc 0002b61c /system/lib/libdvm.so (_Z12dvmInterpretP6ThreadPK6MethodP6JValue + b8)
#11 pc 00060596 /system/lib/libdvm.so (_Z14dvmCallMethodVP6ThreadPK6MethodP6ObjectbP6JValueSt9__va_list + 151)
#12 pc 00049d5a /system/lib/libdvm.so
#13 pc 0004dec2 /system/lib/libandroid_runtime.so
#14 pc 0004ebe6 /system/lib/libandroid_runtime.so (_ZN7android14AndroidRuntime5startEPKcS2_ + 161)
#15 pc 4001a090 /system/bin/app_process
#16 pc 0000e41e /system/lib/libc.so (__libc_init + 31)
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---

可以很清晰地看出崩溃发生在msg函数的某个偏移,pc为00000df2,可以通过addr2line很方便地转换为出错的代码行号。
addr2line -C -f -e libxxx.so 00000df2

五. Proguard混淆配置
避免混淆Bugrpt SDK,请在Proguard混淆文件中配置:

-keep class com.netease.nis.bugrpt.** {*;}

六. 配置mapping

生成APK的时候一般都需要进行混淆处理,此时崩溃发生时产生的崩溃堆栈信息都是混淆后的符号,不便于排查BUG。为了能正确地还原回源码时的堆栈,需要配置一下mapping.txt文件,让“云捕”自动化进行反混淆处理。
混淆处理时,利用proguard在混淆后会生成一个mapping.txt文件,该文件地址Android Studio则是根据配置生成在指定目录下。

Android Studio:

只需要把这个mapping.txt文件上传到后台即可。登录云捕系统,选择您的APP后点击“上传mapping“

七.高级设置:
我们提供UserStrategy类作为Bugrpt的初始化扩展,开发者可以传入一些自定义信息。通过以下方式传入:

Context appCtx = this.getApplicationContext();
UserStrategy strategy = new UserStrategy(appCtx);
//...在这里设置strategy的属性,在bugrpt初始化时传入
CrashHandler.init(appCtx, strategy);

UserStrategy与CrashHandler类的主要API:

  • 设置渠道:
    Bugrpt默认读取AndroidManifest.xml文件中渠道信息,可通过该接口修改渠道信息。

    strategy.setChannel("myChannel");
  • 设置用户账户:
    Bugrpt可以设置用户的账户信息,方便开发者针对性排错。

    strategy.setUserId("myUserID")
  • 设置场景:
    Bugrpt可以设置崩溃场景。

    CrashHandler.setUserScene("myScene");
  • 设置自定义Map参数对:
    Bugrpt支持用户自定义Map参数可以保存发生Crash时的一些自定义的环境信息。在发生Crash时会随着异常信息一起上报并在页面展示。

    CrashHandler.addUserParam("key", "value");

    注意:最多可以有9对自定义的key-value(超过则添加失败),key限长50字节、value限长200字节,过长截断。

  • 主动上报开发者catched的异常
    开发者可能会关注到某个重要异常的catch情况,我们提供了这样的接口:

    try{
    //...
    }catch (Exception e){
    CrashHandler.uploadCatchedException(e);
    }
  • 开发者主动上传信息接口
    为了方便开发者跟踪代码的执行情况,通过主动上传信息接口获取当前程序执行的一些信息(开发者记录的信息+堆栈信息)。使用示例:

    CrashHandler.uploadTrackRecord("myTrackLog");
  • 开发者记录面包屑接口
    开发者通过面包屑功能,追踪程序执行的路径信息,这些信息在App Crash的时候一并上传。使用示例:

    CrashHandler.leaveBreadcrumb("track message");
  • ReLinker.loadLibrary接口
    为了防止Android系统本身的安装逻辑bug导致的java.lang.UnsatisfiedLinkError致命错误,集成了Relinker类的loadLibrary接口,用来替代System.loadLibrary接口。使用说明:
    在原本使用System.loadLibrary调用处

    System.loadLibrary("mylib");

    替换为Relinker.loadLibrary

    ReLinker.loadLibrary(this.getApplicationContext(),"mylib");






网易除了推出了云捕外还推出了云加密,下面是对应的链接:
网易云加密

Bugly

官方地址
Bugly 相对功能会比网易云捕的功能强大些,但是就基本Crash跟踪的话和网易云捕使用方法类似。下面是Bugly的四大核心功能,个人偏向推荐使用这个平台。

一. 库文件导入

如果您使用Gradle编译Apk,我们强烈推荐您使用自动接入方式配置库文件。Bugly支持JCenter仓库和 Maven仓库。
方式1:自动导入(推荐)
为了实现更加灵活的配置,Bugly SDK(2.1.5及以上版本)和NDK(SO库)目前已经分开成两个独立的仓库:

SDK:com.tencent.bugly:crashreport
NDK:com.tencent.bugly:nativecrashreport

其中,集成Bugly NDK时,需要同时集成Bugly SDK。
单独集成Bugly SDK
在Module的build.gradle文件中添加依赖和属性配置:

dependencies {
compile 'com.tencent.bugly:crashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.1.5
}

同时集成Bugly SDK和NDK
在Module的build.gradle文件中添加依赖和属性配置:

android {
defaultConfig {
ndk {
// 设置支持的SO库架构
abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
}
}
}
dependencies {
compile 'com.tencent.bugly:crashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.1.5
compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.2.0
}

注意:自动集成时会自动包含Bugly SO库,建议在Module的build.gradle文件中使用NDK的“abiFilter”配置,设置支持的SO库架构。
如果在添加“abiFilter”之后Android Studio出现以下提示:

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.

则在项目根目录的gradle.properties文件中添加:

android.useDeprecatedNdk=true

为了使APP Crash堆栈的可读性更高,建议您配置符号表文件,更准确地定位问题:
纯Java代码的工程:只需要配置混淆后生成的Mapping文件即可;
含有Native代码的工程:建议配置符号表工具从Debug SO中提取的Symbol符号表文件。

Bugly支持手动和自动配置两种方式,具体的配置方法请参考如下:

二. Bugly Android符号表配置

  • 什么是符号表?

符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示:
<起始地址> <结束地址> <函数> [<文件名: 行号>]

  • 为什么要配置符号表
    为了能快速并准确地定位用户APP发生Crash的代码位置,Bugly使用符号表对APP发生Crash的程序堆栈进行解析和还原。

  • 自动配置:使用Android Studio插件

Bugly插件最新版本为:1.3.9,注意插件位于JCenter仓库。
在项目的buid.gradle文件的dependencies(buildscript部分)中添加:

classpath 'com.tencent.bugly:symtabfileuploader:1.3.9'

其中1.3.9为插件版本号
在module的buid.gradle文件的顶部添加:

apply plugin: 'bugly'
bugly {
appId = '<App ID>'
appKey = '<App Key>'
}

除了appId和appKey之外,还可以设置其他属性,属性列表如下:
属性 值 说明
appId String App ID
appKey String App Key
execute boolean 插件开关
upload boolean 上传开关
outputDir String 符号表文件输出路径

/build.gradle文件如下:

buildscript {
repositories {
jcenter()
}
dependencies {
...
classpath 'com.tencent.bugly:symtabfileuploader:1.3.9'
}
}}

其中”1.3.9”为Bugly插件版本号,更新插件只需要修改这个版本号并Rebuild一下工程即可。

//build.gradle文件如下:

apply plugin: 'bugly'
...
bugly {
appId = '900000000'
appKey = 'abcdefghijklmn'
}

项目应用了Bugly插件之后,Gradle会新建出一个“uploadReleaseSymtabFile”的任务,该任 务被“assembleRelease”任务依赖,即在Release编译时执行。

uploadReleaseSymtabFile任务将执行以下动作:
当项目使用了Proguard,将自动上传生成的mapping文件;
当项目使用了NDK,将自动扫描Debug SO文件,生成符号表文件(zip)并自动上传。
其中查找Debug SO文件时,首先会扫描默认的NDK路径,如果未找到,将继续扫描 项目路径。

三、参数配置

在AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />

请避免混淆Bugly,在Proguard混淆文件中增加一行配置:

-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}

四、最简单的初始化

获取APP ID并将以下代码复制到项目Application类onCreate()中,Bugly会为自动检测环境并完成配置:

CrashReport.initCrashReport(getApplicationContext(), "注册时申请的APPID", false);

为了保证运营数据的准确性,建议不要在异步线程初始化Bugly。

第三个参数为SDK调试模式开关,调试模式的行为特性如下:

● 输出详细的Bugly SDK的Log
● 每一条Crash都会被立即上报;
● 自定义日志将会在Logcat中输出。

建议在测试阶段建议设置成true,发布时设置为false。
此外,Bugly2.0及以上版本还支持通过“AndroidManifest.xml”来配置APP信息。如果同时又通过代码中配置了APP信息,则最终以代码配置的信息为准。

在“AndroidManifest.xml”的“Application”中增加“metadata”配置项:

<application
<!-- 配置APP ID -->
<meta-data
android:name="BUGLY_APPID"
android:value="<APP ID>" />
<!-- 配置APP版本号 -->
<meta-data
android:name="BUGLY_APP_VERSION"
android:value="<APP Version>" />
<!-- 配置APP渠道号 -->
<meta-data
android:name="BUGLY_APP_CHANNEL"
android:value="<APP Channel>" />
<!-- 配置Bugly调试模式(true或者false)-->
<meta-data
android:name="BUGLY_ENABLE_DEBUG"
android:value="<isDebug>" />
</application>

不同于“android:versionName”,“BUGLY_APP_VERSION”配置的是Bugly平台的APP版本号。

通过“AndroidManifest.xml”配置后的初始化方法如下:

CrashReport.initCrashReport(getApplicationContext());

同样 Bugly也提供了UserStrage功能,也就是从功能上看网易云盘有的功能Bugly都有,而Buyly还具备一些网易云盘没有的特色功能如ANR等。
要进一步了解这些功能可以查看如下链接:

https://bugly.qq.com/androidmore
https://bugly.qq.com/document
https://bugly.qq.com/betaDocument

在开始推荐之前先给大家一个建议,编程是一个实践性很强的技术,不要关看这些资料还得多动手实践:
同时记住几句话摘自RxJava Essentials一书的结尾:

Remember that Observable sequences act like rivers: they flow. You can filter a river, you can transform a river, you can combine two rivers into one, and it will still flow. In the end, it will be the river you want it to be.

两本书:

给 Android 开发者的 RxJava 详解
深入浅出RxJava
RxJava官网
RxWeekend——RxJava周末狂欢
RxJava操作符
Top 7 tips for Rxjava on Android
Architecting Android with RxJava
来自Github的资源:

https://github.com/kaushikgopal/RxJava-Android-Samples
https://github.com/cn-ljb/rxjava_for_android
https://github.com/THEONE10211024/RxJavaSamples

要是这些你都啃完了,还不会你发邮件给我,我手把手教你!不过一定不会有这种现象发生的,上面全部都是干货!不过我自己也没完全看完,太多了,需要什么再看什么。