android-best-practices, 由于Futurice开发人员,不要对Android开发进行任何操作

分享于 

34分钟阅读

GitHub

  繁體 雙語
Do's and Don'ts for Android development, by Futurice developers
  • 源代码名称:android-best-practices
  • 源代码网址:http://www.github.com/futurice/android-best-practices
  • android-best-practices源代码文档
  • android-best-practices源代码下载
  • Git URL:
    git://www.github.com/futurice/android-best-practices.git
    Git Clone代码到本地:
    git clone http://www.github.com/futurice/android-best-practices
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/futurice/android-best-practices
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    Android开发最佳实践

    遵循以下准则避免重新创建轮子。 从Android开发者的经验中学习到的经验。 如果你对iOS或者 Windows Phone 开发感兴趣,请务必检查我们的iOS Good最佳实践Windows 应用程序开发最佳实践

    Android ArsenalSpice Program Sponsored

    摘要

    use Gradle and its default project structurePut passwords and sensitive data in gradle.propertiesuse the Jackson library parse JSON datadon't write your own HTTP client, use OkHttp librariesAvoid Guava and use only a few libraries due the 65k method limitSail carefully when choosing between Activities and FragmentsLayout XMLs are code, organize them welluse styles avoid duplicate attributes in layout XMLsuse multiple style files avoid a single huge onekeep your colors.xml short and DRY, just define the palettealso keep dimens.xml DRY, define generic constantsdo not make a deep hierarchy of ViewGroupsAvoid client-side processing for WebViews, and beware of leaksuse JUnit for unit tests, Espresso for connected (UI) tests, and AssertJ-Android for easier assertions in your Android testsalways use ProGuard or DexGuarduse SharedPreferences for simple persistence, otherwise ContentProvidersuse Stetho debug your applicationuse Leak Canary find memory leaksuse continuous integration

    SDK

    在主目录或者其他应用程序独立位置处放置你的SDK。 IDE的一些发行版包括安装时的SDK,并且可以将它的置于与IDE相同的目录下。 如果你需要升级 IDE,这可能会很糟糕,因为你可能会丢失SDK安装,从而导致一个冗长乏味的重新下载。

    同时避免将SDK放在可能需要 root 权限的系统级别目录中,以避免权限问题。

    构建系统

    你的默认选项应该是Gradle 使用 Android Gradle插件。

    重要的是,应用程序流程的构建是由Gradle文件定义的,而不是依赖于特定于IDE的配置。 这允许在工具之间建立一致的构建,更好地支持 持续集成 系统。

    项目结构

    除非Gradle有很大的灵活性,但是除非你有强制性的理由去做,否则你应该接受它的默认结构来简化构建脚本。

    Gradle配置

    通用结构。 遵循谷歌关于Android的指南。

    我们建议你在定义最低API要求之前,先查看一下Android版本的使用图( )。 记住,给定的统计数据是全球统计信息,在针对特定地区/人口统计市场时可能有所不同。 值得注意的是,一些材料设计特性仅在 Android 5.0 ( API级别 21 ) 和 上面 上可用。 而且,从 API 21中,不再需要multidex支持库了。

    小任务代替(。shell,python,Perl等) 脚本,你可以在Gradle中完成任务。 只要遵循文档的文档,就可以了解更多细节。 Google还提供了一些有用的 Gradle菜谱,特别适用于 Android。

    你需要定义发布版本的应用程序的build.gradle 中的 Passwords。 以下是你应该避免的内容:

    不要这样做。 这将出现在版本控制系统中。

    signingConfigs {
     release {
     // DON'T DO THIS!! storeFile file("myapp.keystore")
     storePassword "password123" keyAlias "thekey" keyPassword "password789" }
    }

    相反,制作一个不应该被添加到版本控制系统的gradle.properties 文件:

    
    KEYSTORE_PASSWORD=password123
    
    
    KEY_PASSWORD=password789
    
    
    
    

    文件由Gradle自动导入,因此你可以在 build.gradle 中使用该文件,如下所示:

    signingConfigs {
     release {
     try {
     storeFile file("myapp.keystore")
     storePassword KEYSTORE_PASSWORD keyAlias "thekey" keyPassword KEY_PASSWORD }
     catch (ex) {
     thrownewInvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
     }
     }
    }

    Maven 依赖解析来导入 jar 文件。 如果在项目中显式包含 jar 文件,则它们将是特定的冻结版本,如 2.1.1。 下载 jars 和处理更新很麻烦,而且 Maven 已经解决了这一问题。 如果可能,应尝试使用 Maven 来解析依赖项,例如:

    dependencies {
     compile 'com.squareup.okhttp:okhttp3:3.8.0'}

    避免使用动态依赖关系解析避免使用动态依赖项版本,如 2.1.+,这可能导致生成的不同和不稳定的生成或者生成之间的不稳定的不一致的差异。 使用 static 版本如 2.1.1 有助于创建更稳定可以预测和可以重复的开发环境。

    使用不同的软件包 NAME 为非发行版生成使用 applicationIdSuffix for调试 build build build build build build build same same same device在同一设备上安装 apk debug。 这将在你的应用发布后特别有价值。

    android {
     buildTypes {
     debug {
     applicationIdSuffix '.debug' versionNameSuffix '-DEBUG' }
     release {
     //.. . }
     }
    }

    使用不同的图标来区分安装在设备上的不同颜色或者覆盖的"调试"标签。 Gradle使这非常容易: 使用默认项目结构,简单地将调试 icon 在 app/src/debug/res 和版本release在 app/src/release/res 中。 你还可以对每个构建类型( 以及 versionName ( 在 上面 示例中) ) 更改应用程序 NAME 插件。

    Android Studio 作为你的主要 IDE

    安卓开发者的推荐IDE是 Android Studio 因为它是由Google开发并不断更新的,对Gradle有很好的支持,包含了一系列有用的监视和分析工具,完全适合安卓开发。

    避免添加特定于studio配置文件的Android,例如 .iml 文件到版本控制系统中,这些配置不适合同事。

    ibm的 Jackson是一个用于JSON序列化和反序列化的Java库,它具有广泛的作用域和通用 API,支持各种处理JSON的方式: 流。内存树模型和传统的json pojo数据绑定。

    Jackson相比,是另一个流行的选择,也是一个较小的库,你可能希望避免 65k 方法限制。 另外,如果你使用

    是开放源代码库的另一个插件,它基于Gson的开发,同时也集成了面向对象技术的开发。

    网络,高速缓存和图像。 有两个针对后端服务器执行请求的解决方案,你应该使用它们,而不是实现自己的客户机。 为了有效地请求HTTP请求和使用更新插件,我们建议在 OkHttp 基础上,提供一个安全。 如果你选择修改,考虑 加载和缓存图像。

    重新创建,毕毕和OkHttp是由同一家公司创建的,因这里他们互相补充的问题不常见。

    滑动插件是加载和缓存映像的另一种选择。 它支持动画 gif,圆形图像和比毕斯更好的性能声明,但也有更大的方法计数。

    RxJava 是一个用于React性编程的库,换句话说,处理异步事件。 这是一个强大的范例,但也有一个陡峭的学习曲线。 我们建议在使用这个库来构建整个应用程序之前采取一些谨慎。 我们已经写了一些博客文章: ,[3],[4]。 ,reference,我们的开源应用程序 Freesound Android广泛使用 2.

    如果你以前没有Rx的经验,首先应将它的应用于来自应用程序api后端的响应。 或者,从应用简单的UI事件处理开始,比如单击事件或者在搜索字段中键入事件。 如果你对Rx技能感到信心并想将它应用到整个架构中,那么将文档写入所有这些技巧。 请记住,另一个不熟悉RxJava的程序员可以能很难维护项目。 尽量帮助他们理解你的代码,也能帮助他们理解你的代码。

    在Android的线程支持和 RxBinding插件中使用RxAndroid插件,以便从现有的Android组件轻松创建可见性。

    Retrolambda 是在Android和其他pre-JDK8平台中使用Lambda表达式语法的Java库。 如果你使用函数式样式,如在RxJava中,它有助于保持代码的紧凑性和可读性。

    Android Studio 为 Java 8提供了代码协助支持。 如果你是lambdas新手,只需使用以下命令即可开始:

    • 只有一个方法的接口是"lambda友好",并且可以折叠成更紧凑的语法
    • 如果不确定参数等,编写一个普通的匿名内部类,然后让 Android Studio 将它折叠成一个 lambda。

    请注意,从 Android Studio 开始,不再需要 Retrolambda了。

    注意:要注意dex方法限制,并避免使用多个库。 Android应用程序打包为一个dex文件时,有一个硬限制为 65536 [1][2][3]。 你将在编译过程中看到一个致命错误,如果你通过了限制。 因此,使用最少的库,使用 dex-method-counts命令行工具确定可以使用哪些库,以便在限制的情况下保持在可用范围内。 特别避免使用 Guava 库,因为它包含超过 13k 个方法。

    activity 和 Fragments

    在社区和Futurice开发人员之间没有达成共识,如何最好地利用 Fragments 和 activity 组织Android体系结构。 Square即使在社区中也有一个用于构建架构的库,大多数都有视图插件,但是这在社区中并不被认为是一种广泛推荐。

    由于Android的api历史,你可以把 Fragments 当作屏幕上的UI。 换句话说,Fragments 通常与UI相关。 可以松散地将 activity 看作是控制器,它们对于生命周期和管理状态尤其重要。 但是,你可能会看到这些角色的变化: activity 可能采用UI角色( 在屏幕之间传递过渡。),而Fragments 可能仅作为控制器使用。 我们建议你仔细地进行航行,因为只有架构。仅仅仅仅是体系结构或者视图的缺点。 这里有一些关于要小心的建议,但是要用盐来表示:

    • 避免使用嵌套的Fragments 插件,因为可以发生matryoshka Bug。 只有当它有意义的时候才使用嵌套的Fragments,或者如果它是。
    • 避免在 activity 中放置太多代码。 只要可能,将它们作为轻量级容器,在你的应用程序中主要是为了生命周期和其他重要的。 更喜欢单个 Fragment activity 而不是普通 activity - 将UI代码放入 Activity的fragment。 这使得它可以重复使用,以防你需要将它更改为驻留在选项卡式布局中或者在多片平板。 除非你做出明确的决定,否则避免 Having 一个没有相应 fragment的Activity。

    Java包结构

    我们建议使用基于xml的基于的包结构来实现代码。 这具有以下优点:

    • 更清晰的特征相关性和界面边界。
    • 促进封装。
    • 更容易理解定义特性的组件。
    • 降低不相关或者共享代码的风险。
    • 更简单的导航:大多数相关类将在一个包中。
    • 更容易删除特征。
    • 简化基于 MODULE 构建结构的转换( 更好的构建时间和即时应用支持)

    另一种方法是,通过创建一个特性来定义包,这是一个复杂的代码库,它的实现灵活性很低,而且实现灵活性也很低。 最重要的是,它妨碍了你根据主要角色理解代码基础的能力: 为应用程序提供功能。

    资源

    名称遵循前缀类型的约定,如在 type_foo_bar.xml 中。 示例:fragment_contact_details.xmlview_primary_button.xmlactivity_main.xml

    如果不确定如何设置布局XML格式,则组织布局 XMLs,下面的约定可能会帮助。

    • 每行一个属性,以 4空格缩进
    • android:id 作为第一个属性
    • 顶部的android:layout_**** 属性
    • 底部的style 属性
    • 在它的自己的行上标记更接近的/>,以方便排序和添加属性。
    • 除了硬代码 android:text 之外,考虑使用设计器属性
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"> 
     <TextViewandroid:id="@+id/name"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:text="@string/name"style="@style/FancyText"/>
     <includelayout="@layout/reusable_part"/>
    </LinearLayout>

    通常,属性 android:layout_**** 应该在布局XML中定义,而其他属性 android:**** 应该保留在样式XML中。 这条规则有例外,但一般情况下。 它的思想是只在布局文件中保留布局( 定位,margin,调整大小) 和内容属性,同时保留所有外观细节的样式文件。

    例外是:

    • android:id 显然应该位于布局文件中
    • LinearLayoutandroid:orientation 通常在布局文件中更有意义
    • android:text 应位于布局文件中,因为它定义了内容
    • 有时,创建定义 android:layout_widthandroid:layout_height的通用样式是有意义的,但是默认情况下,这些样式应该出现在布局文件中

    使用样式。 由于视图非常常见,所以每个项目几乎都需要正确使用样式。 至少,你应该对应用程序中的大多数文本内容具有共同的样式,例如:

    <stylename="ContentText">
     <itemname="android:textSize">@dimen/font_normal</item>
     <itemname="android:textColor">@color/basic_black</item>
    </style>

    应用于 TextViews:

    <TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/price"style="@style/ContentText"/>

    你可能需要对按钮进行同样的操作,但仍然不要停止。 超越并将一组相关和重复的android:**** 属性移到通用样式。

    将大型样式文件分割为其他文件。 你不需要有单个 styles.xml 文件。 Android SDK支持它的他文件,有关 NAME styles的任何魔术,问题是XML标签 <style> inside的文件。 因此,你可以有文件 styles.xmlstyles_home.xmlstyles_item_details.xmlstyles_forms.xml。 在构建系统中承载某些含义的资源目录名称不同,res/values 中的文件名可以是任意的。

    colors.xml 是调色板。colors.xml 中不应该仅仅是从颜色 NAME 到RGBA值的映射。 不使用它来定义不同类型按钮的RGBA值。

    不要这样做:

    <resources>
     <colorname="button_foreground">#FFFFFF</color>
     <colorname="button_background">#2A91BD</color>
     <colorname="comment_background_inactive">#5F5F5F</color>
     <colorname="comment_background_active">#939393</color>
     <colorname="comment_foreground">#FFFFFF</color>
     <colorname="comment_foreground_important">#FF9D2F</color>
    . . .
     <colorname="comment_shadow">#323232</color>

    如果需要,可以轻松开始以这里格式重复vmkernel值,这使得更改基本颜色变得更加复杂。 另外,这些定义与一些上下文相关,比如"按钮"或者"评论",并且应该在按钮样式中,而不是在 colors.xml 中。

    请执行以下操作:

    <resources>
     <!-- grayscale --> <colorname="white"> #FFFFFF</color>
     <colorname="gray_light">#DBDBDB</color>
     <colorname="gray"> #939393</color>
     <colorname="gray_dark"> #5F5F5F</color>
     <colorname="black"> #323232</color>
     <!-- basic colors --> <colorname="green">#27D34D</color>
     <colorname="blue">#2A91BD</color>
     <colorname="orange">#FF9D2F</color>
     <colorname="red">#FF432F</color>
    </resources>

    从应用程序的设计器请求这里选项板。 名称不需要作为"绿色","蓝色",等等 名称,如"brand_primary","brand_secondary","brand_negative"完全可以接受的颜色名称。 格式化颜色将使更改或者重构颜色变得容易,也会显式地显示不同颜色的颜色。 通常,对于审美用户界面来说,减少使用的颜色是很重要的。

    你需要定义一个典型的间距和字体大小,你也应该定义一个典型的间距和字体大小,基本相同的目的与颜色。 二维 file:的一个很好的例子

    <resources>
     <!-- font sizes --> <dimenname="font_larger">22sp</dimen>
     <dimenname="font_large">18sp</dimen>
     <dimenname="font_normal">15sp</dimen>
     <dimenname="font_small">12sp</dimen>
     <!-- typical spacing between two views --> <dimenname="spacing_huge">40dp</dimen>
     <dimenname="spacing_large">24dp</dimen>
     <dimenname="spacing_normal">14dp</dimen>
     <dimenname="spacing_small">10dp</dimen>
     <dimenname="spacing_tiny">4dp</dimen>
     <!-- typical sizes of views --> <dimenname="button_height_tall">60dp</dimen>
     <dimenname="button_height_normal">40dp</dimen>
     <dimenname="button_height_short">32dp</dimen>
    </resources>

    你应该在页边距和页边距中使用 spacing_**** 维度,而不是硬编码值,这与通常处理字符串时。 这将提供一致的look-and-feel,同时更易于组织和更改样式和布局。

    strings.xml

    用类似命名空间的键命名字符串,并且不要害怕重复两个或者多个键的值。 语言很复杂,所以需要命名空间来产生上下文和中断歧义。

    <stringname="network_error">Network error</string>
    <stringname="call_failed">Call failed</string>
    <stringname="map_failed">Map loading failed</string>
    <stringname="error_message_network">Network error</string>
    <stringname="error_message_call">Call failed</string>
    <stringname="error_message_map">Map loading failed</string>

    不在全部大写中写入字符串值。 遵循普通文本约定(。比如,大写大写字符)。 如果需要全部显示字符串,那么在TextView上使用例如属性 textAllCaps

    <stringname="error_message_call">CALL FAILED</string>
    <stringname="error_message_call">CALL FAILED</string>

    避免views层次的视图。 有时,你可能希望仅仅添加另一个 LinearLayout,以完成视图的排列。 这种情况可能发生:

    <LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"> 
     <RelativeLayout. . .
    > 
     <LinearLayout. . .
    > 
     <LinearLayout. . .
    > 
     <LinearLayout. . .
    > 
     </LinearLayout>
     </LinearLayout>
     </LinearLayout>
     </RelativeLayout>
    </LinearLayout>

    即使在布局文件中没有明确见到这个问题,如果你将( 在Java中) 视图膨胀到它的他视图中。

    可能会出现几个问题。 由于处理器需要处理复杂的UI树,你可能会遇到性能问题。 另一个更严重的问题是 StackOverflowError的可能性。

    因此,尽量将视图的层次保持为平面: 了解如何使用 ConstraintLayout插件,如何优化布局,以及使用<merge> 标签。

    注意与WebViews相关的问题。 当你必须显示一个网页时,例如对于新闻文章,避免做客户端处理来清理 HTML,而不是从后端程序员那里请求一个""HTML。 当 WebViews保留对它的的引用时,它们也可以泄漏内存,而不是绑定到 ApplicationContext。 避免对简单文本或者按钮使用web视图,更喜欢平台的小部件。

    测试框架

    在单元测试使用 Plain在JVM上使用dependency免费单元测试is最好使用 Junit。

    为了在Android构建系统中改进对JUnit的支持, Robolectric为开发速度提供了测试框架,作为测试框架,被提升为一个测试框架。 然而,在Robolectric下测试是不准确和不完整的,因为它通过提供Android平台的mock 实现来工作,这不保证。 相反,使用基于JVM的单元测试和设备集成测试的组合。

    咖啡让编写UI测试容易。

    ibm AssertJ assert AssertJ扩展库使你可以轻松测试Android特定组件,如Android支持,Google Play Services 和Appcompat库。

    测试断言看起来像:

    // Example assertion using AssertJ-AndroidassertThat(layout).isVisible()
    . isVertical()
    . hasChildCount(5);

    仿真器

    Android SDK 模拟器 ( 特别是x86变体)的性能在近年来显著提高,现在大多数日常开发方案都足够了。 但是,你不应该低估确保应用程序在实际设备上正确运行的价值。 当然,对所有可能的设备进行测试并不实用,因此将精力集中在拥有大型市场份额和与应用程序最相关的设备上。

    混淆器配置

    在Android项目中,通常使用混淆器来缩小和混淆包代码。

    你是否使用混淆器取决于你的项目配置。 通常你会在构建发布版本时配置Gradle来使用混淆器。

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

    为了确定哪些代码必须保留,哪些代码可以丢弃或者混淆,你必须为代码指定一个或者多个入口点。 这些入口点通常是具有主方法。小程序。activity。等等 Android框架的类。 SDK_HOME/tools/proguard/proguard-android.txt 使用 上面 配置,自定义项目特定混淆器规则,如 my-project/app/proguard-rules.pro 中定义的那样,将被附加到缺省配置。

    混淆器相关的一个常见问题是,在启动时使用 ClassNotFoundException 或者 NoSuchFieldException 或者类似的方式查看应用程序崩溃,尽管构建命令( 例如 )。 assembleRelease ) 成功而无警告。 这意味着其中之一是:

    • 混淆器删除了类。enum。方法。字段或者注释,考虑到它是不需要的。
    • 混淆了( 重命名)的类,enum 或者字段 NAME,但它由原始 NAME 使用,通过Java反射使用 换句话说,。

    支票 app/build/outputs/proguard/release/usage.txt 查看所涉及的对象是否已经被删除。 支票 app/build/outputs/proguard/release/mapping.txt 查看所讨论的对象是否已经被混淆。

    为了防止混淆者从你的needed类或者类成员 stripping,请向你的混淆器配置添加一个 keep 选项:

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

    要防止混淆混淆ProGuard混淆的类或者类成员,添加一个 keepnames:

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

    阅读更多关于混淆器的信息,例如。

    在项目的早期构建和测试版本构建来检查混淆器规则是否正确地保留了你的依赖关系。 同时,每当你包含新的库或者更新它们的依赖关系时,就可以在设备上发布。 不要等到你的应用程序为 finally 版" 1.0"发布版本,你可能会得到几个不好的意外和短时间来修复它们。

    向用户发布你发布的每个版本的文件,提示。 通过保留每个版本的mapping.txt 文件的副本,确保可以在用户遇到 Bug 并提交混淆的堆栈跟踪时调试问题。

    如果你需要硬核心工具来优化,特别是obfuscating的发布代码,考虑 DexGuard,这是由构建混淆程序的同一个团队制作的商业软件。 它还可以轻松分割Dex文件以解决 65k 种方法限制。

    基于的数据存储

    SharedPreferences

    如果只需要保持简单值,并且应用程序在单个进程中运行,那么SharedPreferences可能就足够了。 这是一个很好的默认选择。

    在某些情况下,SharedPreferences不适合:

    • 性能: 数据很复杂或者有很多
    • 多个进程访问数据: 你拥有在自己的进程中运行的小部件或者远程服务,并且需要同步的数据
    • 基于关系的关系数据数据的不同部分是关系的,并且你希望强制这些关系保持不变。

    还可以将更复杂的对象序列化为JSON以存储它们并在检索时反序列化它们。 当这样做时,你应该考虑权衡,因为它可以能不特别具有表现性,也不可以维护。

    ContentProviders

    如果SharedPreferences不够,那么应该使用平台标准 ContentProviders,它是快速的和进程安全的。

    ContentProviders的单一问题是设置它们所需的样板代码数量,以及低质量的教程。 但是,可以使用诸如这样的库生成内容库,这显著地减少了工作的负担。

    你仍然需要编写一些解析代码来从SQLite列读取数据对象,反之亦然。 可以序列化数据对象,例如使用 Gson,并且只保留结果字符串。 在这种方式下,你失去了性能,但是你不需要为数据类的所有字段声明一个列。

    使用 ORM

    除非你有非常复杂的数据,并且你需要非常复杂的数据,否则我们通常不推荐使用对象关系映射库。 它们往往是复杂的,需要时间来学习。 如果你决定使用 ORM,那么应该注意它是否是面向服务的进程安全如果你的应用程序需要它,就像许多现有的ORM解决方案令人惊讶的一样。

    使用 Stetho

    是与浏览器工具的Chrome 桌面开发者集成的Android应用程序的调试桥。 使用 Stetho,你可以轻松检查你的应用程序,特别是网络流量。 它还允许你轻松检查和编辑SQLite数据库和应用程序中的共享首选项。 但是,应确保Stetho仅在调试版本中启用,而不在版本生成变体中启用。

    另一种替代方法是 ,虽然提供了稍微简化的功能,但在设备上显示的日志仍然有用,而不是所需的复杂连接的Chrome 浏览器设置。

    使用 LeakCanary

    是一个库,它使运行时检测和标识内存泄漏成为应用程序开发过程中更常规的一部分。 有关配置和用法的详细信息,请参见库 。 只需记住在发布版本中只配置"无操作"依赖项 !

    使用 持续集成

    持续集成 系统允许你在每次向版本控制推送更新时自动生成和测试项目。 持续集成 还运行 static 代码分析工具,生成APK文件并分发它们。 在代码中,Checkstyle是确保代码质量的工具,而Findbugs在代码中寻找 Bug。

    有各种各样的持续集成 软件提供不同的功能。 如果你的项目是开源的,定价计划可能是免费的。 如果你有本地服务器,是个不错的选择,另外,如果你计划使用基于云的服务, Travis也是推荐选择。

    感谢

    确认

    logo

    本项目由美国 项目,我们的开源和社交冲击程序由

    许可证

    Futurice Oy创作共用属性国际( CC由 4.0 )


    DOS  dos-donts  
    相关文章