Android 开发最佳实践(Futurice 版)完整指南:Gradle 构建、资源组织与 ProGuard 实战
文档教程移动开发【免费下载链接】android-best-practicesDos and Donts for Android development, by Futurice developers项目地址https://gitcode.com/gh_mirrors/an/android-best-practices点击查看免费下载本指南以 Futurice 团队多年 Android 实战沉淀的《android-best-practices》为骨架对应仓库根目录 README.md 及其多语言译本如 西语版系统梳理从构建系统、依赖管理、代码与资源组织到测试、调试、内存泄漏检测与发布加固的完整最佳实践链路。读完本文你将掌握一套可直接落地的 Android 工程规范如何用 Gradle 安全管理签名密钥、如何用规范的 XML 资源组织避免布局与样式的失控、如何规避 65k 方法数限制、如何正确配置 ProGuard 并排查混淆引发的崩溃以及如何用 Stetho 与 LeakCanary 提升调试与内存治理效率。一、总览这些建议从何而来这些实践并非纸上谈兵而是来自 Futurice 公司一线 Android 开发者的真实经验教训其目的在于避免重复发明轮子Avoid reinventing the wheel。文档同时面向开发流程的各个环节其核心主张可以归纳为构建默认使用 Gradle 及其推荐的项目结构构建过程由 Gradle 文件定义而非 IDE 配置。安全密码与敏感数据一律放入不纳入版本控制的gradle.properties。依赖优先使用成熟库Jackson/OkHttp/Retrofit/Picasso/Glide不自己造 HTTP 客户端轮子同时警惕 65k 方法数限制谨慎控制库的数量。代码组织精心规划 Activities 与 Fragments 的职责边界、Java 包结构与资源文件layouts、styles、colors、dimens、strings。质量用合适的测试框架、模拟器、ProGuard、Stetho、LeakCanary 保证发布质量与可维护性。仓库以单一 Markdown 文档承载全部内容README.md并提供了包含 中文、法语、日语、韩语、葡萄牙语、俄语、西语、土耳其语、越南语 在内的多语言版本且全文基于 Creative Commons Attribution 4.0 International (CC BY 4.0) 协议开放见 LICENSE方便团队将其内化为自己的工程规范。二、开发环境Android SDK 的安放位置核心建议把 Android SDK 放在home目录或其他与应用程序无关的独立位置。有些 IDE 发行版在安装时会顺带把 SDK 放到 IDE 自身目录之下这会在你升级或重装 IDE 时带来隐患——很可能连 SDK 一起被覆盖或删除迫使你重新经历漫长而繁琐的下载过程。同时要避免把 SDK 放到需要sudo权限的系统级目录如果你的 IDE 以普通用户身份运行而非 root后续 SDK 组件的安装与更新会频繁遭遇权限问题。三、构建系统Gradle 与推荐的项目结构3.1 为什么默认选择 Gradle文档明确建议将 Gradle 作为默认构建系统理由是它让以下工作变得简单创建应用的不同flavor变体用脚本完成简单任务管理与下载依赖自定义 keystore以及更多……Ant 作为旧构建系统已于 2015 年废弃Android 的 Gradle 插件改由 Google 亲自开发与维护。关键原则应用的构建过程必须由 Gradle 文件定义而不是依赖 IDE 特定的配置。这样才能保证在不同工具链之间构建结果一致并为持续集成CI系统提供良好支持。3.2 采用 Gradle 的默认项目结构尽管 Gradle 在项目结构上提供了很大灵活性除非你有令人信服的理由否则应当采用它的默认结构基于 source set 的main、androidTest等目录划分这会大幅简化构建脚本。仓库中 中文译本 对这种新旧结构的差异做了更直观的对照旧式 Ant Eclipse ADT 结构把assets、libs、res、src、AndroidManifest.xml平铺在根目录而新式 Gradle 结构则引入顶层app模块内部再分src/main、src/androidTest并将第三方库项目如library-foobar独立为同级模块通过根目录的settings.gradle引用。3.3 Gradle 配置细节通用结构遵循 Google 官方的 Gradle for Android 指南。小任务与其写 shell、Python、Perl 等外部脚本不如直接在 Gradle 中定义任务Task遵循 Gradle 官方文档即可。密码与敏感数据重点在应用模块的build.gradle中为release构建定义signingConfigs时切勿把密码硬编码进构建文件signingConfigs { release { storeFile file(myapp.keystore) storePassword password123 keyAlias thekey keyPassword password789 } }这样做会把密钥信息泄露进版本控制系统。正确做法是创建一个不加入版本控制的gradle.properties文件KEYSTORE_PASSWORDpassword123 KEY_PASSWORDpassword789该文件会被 Gradle 自动导入因此在build.gradle中可以直接引用并配合try/catch在缺失时给出清晰提示signingConfigs { release { try { storeFile file(myapp.keystore) storePassword KEYSTORE_PASSWORD keyAlias thekey keyPassword KEY_PASSWORD } catch (ex) { throw new InvalidUserDataException(Deberías definir tu KEYSTORE_PASSWORD y KEY_PASSWORD en gradle.properties.) } } }提示gradle.properties位于项目根目录时对模块级build.gradle全局可见务必把该文件加入.gitignore并可为团队成员提供一份不含真实密码的模板。优先使用 Maven 依赖解析而非导入 jar 文件显式将 jar 放进项目意味着版本被冻结在特定版本上下载与管理更新非常繁琐而 Maven 依赖解析恰好解决了这个问题这也是 Gradle 推荐的做法。例如dependencies { implementation com.squareup.okhttp:okhttp:2.2.0 implementation com.squareup.okhttp:okhttp-urlconnection:2.2.0 }避免动态依赖版本不要使用2.1.这类动态解析它会导致构建不稳定、不同构建之间出现难以追踪的行为差异使用2.1.1这样的静态版本有助于打造更稳定、可预测、可复现的开发环境。为非 release 构建使用不同的包名借助applicationIdSuffix让debug与release两个 APK 可以同时安装在同一台设备上自定义构建类型若有需要也可照做这在应用上架后尤其有价值android { buildTypes { debug { applicationIdSuffix .debug versionNameSuffix -DEBUG } release { // ... } } }配套实践用不同图标区分设备上的构建版本例如不同颜色或叠加 debug 字样。借助默认项目结构只需把 debug 图标放进app/src/debug/res、release 图标放进app/src/release/resGradle 会自动按构建类型选择资源。此外还可以按构建类型修改应用名与versionName。3.4 IDE 与文本编辑器原则编辑器是个人选择但必须让它适配项目结构与构建系统。推荐 Android Studio由 Google 开发并高频更新对 Gradle 支持良好内置大量实用的监测与分析工具专为 Android 开发定制。也可以使用 Vim、Sublime Text、Emacs 等纯文本编辑器但此时必须自己用命令行 Gradle 与adb完成构建与调试。Eclipse ADT 已不再是好的选择Google 于 2015 年停止对 ADT 的支持并建议用户尽快迁移到 Android Studio。无论选择哪种工具都不要把编辑器专属配置文件如 Android Studio 的.iml文件提交到版本控制——它们通常包含你本机特有的配置无法在同事的机器上正常工作。最后请善待团队其他开发者不要强迫他们更换自己更顺手的工具。四、依赖选型库的取舍与 65k 方法数限制4.1 JSON 解析Jackson 为主Gson 为备Jackson 是 Java 领域的 JSON 序列化/反序列化库支持三种 JSON 处理方式流式streaming、内存树模型in-memory tree model与传统的JSON-POJO 数据绑定API 覆盖面广且灵活。Gson 同样是热门选择但它比 Jackson 更小——在需要规避 65k 方法数限制的场景下可以考虑以 Gson 替代。其他备选还有 Json-smart 与 Boon JSON。4.2 网络、缓存与图片不要自己写 HTTP 客户端请求后端服务器有几套久经实战考验的方案应直接采用而非自行实现客户端Volley 或 Retrofit发起网络请求。Volley 还附带图片加载与缓存能力。若选 Retrofit建议配 Picasso 做图片加载与缓存、OkHttp 做更高效的 HTTP 请求。Retrofit、Picasso、OkHttp 出自同一家公司Square彼此配合良好、兼容性问题少见OkHttp 也可以与 Volley 配合使用。Glide 是另一款图片加载/缓存方案支持 GIF 动图与圆形图片宣称性能优于 Picasso但方法数也更多。4.3 RxJava强大的异步范式谨慎落地RxJava 是响应式编程库用于处理异步事件。它是一个强大且前景广阔的范式但也与传统思维方式差异巨大、容易让人困惑文档明确建议在使用它架构整个应用之前保持谨慎。渐进式采用路径如果对 Rx 没有经验先只把它用于后端 API 响应的处理随后再逐步应用到 UI 事件处理如点击事件、搜索框输入事件若确信自己的 Rx 水平并想将其用于整个架构务必为所有棘手部分编写 Javadocs——其他不熟悉 RxJava 的开发者可能很难维护这样的项目请尽力帮助他们理解你的代码与 Rx。补充仓库英文版 README.md 还提到用 RxAndroid 提供 Android 线程支持、用 RxBinding 从既有 Android 组件轻松创建 Observable并指出从 Android Studio 3.0 起 Java 8 lambda 支持已内建、不再需要 Retrolambda。4.4 Retrolambda在旧平台使用 Lambda 语法Retrolambda 允许在 Android 及其他 JDK8 之前的平台上使用 Lambda 表达式语法能让代码更紧凑易读尤其适合函数式风格如与 RxJava 搭配。Android Studio 对 Java 8 lambda 提供代码辅助新手可以这样入手任何只有一个方法的接口都是lambda 友好的可以折叠成更紧凑的语法对参数等细节拿不准时先写普通匿名内部类再让 Android Studio 帮你折叠成 lambda。4.5 警惕 dex 方法数限制慎用库Android 应用打包为 dex 文件后存在65536 个引用方法的硬性上限一旦超过就会编译失败。因此尽量使用最少数量的库用 dex-method-counts 工具统计各库的方法数确定哪些库组合能让你保持在上限之下尤其避免使用 Guava它包含约 13k 个方法是方法数大户。说明英文版补充提到从 API 21 起 multidex 支持库不再是必需README.md 的 Gradle 配置一节但 65k 单 dex 限制的告诫依旧适用于老设备与旧 API 场景。五、Activities 与 Fragments谨慎驶过架构选择的暗礁社区与 Futurice 内部对如何用 Fragments/Activities 组织架构并无统一共识。Square 甚至推出过主要基于 View 构建架构的 mortar 库来绕开 Fragments但这并未被社区广泛认可为推荐实践。受 Android API 历史影响可以粗略地把Fragments 视为屏幕上的 UI 片段通常与界面相关把Activities 视为控制器尤其对生命周期与状态管理重要。不过实际中角色常有交叉Activities 可能承担 UI 职责如屏幕间转场Fragments 也可能只作为控制器使用。文档的建议是小心驶得万年船在充分了解信息的前提下做决策因为纯 Fragments、纯 Activities 或纯 Views 的架构各有弊端。需要警惕的要点尽量避免嵌套 Fragments嵌套容易引发套娃式matryoshkabug仅在有明确理由时使用例如横向滑动的 ViewPager 内的 Fragment位于类似屏幕的 Fragment 内部或确属深思熟虑的决策。避免在 Activities 中堆砌过多代码尽量让 Activity 保持轻量容器角色主要用于生命周期与 Android 系统 API 交互。优先使用单 Fragment 的 Activity而非裸 Activity——把 UI 代码放进 Activity 对应的 Fragment这样将来要改为标签页布局或多 Fragment 平板界面时可以直接复用除非有充分的决策理由避免出现没有对应 Fragment 的 Activity。不要滥用 Android API level如果应用内部大量依赖 Intent 进行通信可能影响 Android 系统或其他应用造成错误或延迟。例如已知的问题是若应用包间用 Intent 做内部通信恰在系统刚启动后打开应用时可能带来数秒的用户体验延迟。六、Java 包结构面向功能的组织方式文档给出的思路是把 Android 的 Java 架构放到 MVC 框架下审视Fragments/Activities 既算控制器、又因显式参与 UI 而算视图因此难以严格归类。建议的做法是Fragments 放进独立的fragments包Activities 数量不超过 23 个时留在顶层包更多时则建activities包。models包存放供 JSON 解析器与 API 响应使用的 POJO。views包存放所有 Views、通知、Action Bar Views、widgets 等adapters作为数据与视图的中介结构通常需要通过getView()导出 View因此可放在views之下。managers包全局性的、贴近 Android 系统的控制器类。utils包数据处理类如 DateUtils。network包负责与后端交互的类。整体上按从离后端最近到离用户最近排列com.futurice.project ├─ network ├─ models ├─ managers ├─ utils ├─ fragments └─ views ├─ adapters ├─ actionbar ├─ widgets └─ notifications说明这是该文档西语版所呈现的按层分包方案仓库英文版 README.md 已演进为更推荐的面向功能feature based分包并列举了依赖边界清晰、利于封装、便于按功能移除代码、易于过渡到模块化构建等收益。团队可根据项目阶段选择适合的方案。七、资源组织布局、样式、颜色、尺寸与字符串7.1 资源命名规范遵循type_foo_bar.xml的命名模式类型前缀 功能 具体对象例如fragment_contact_details.xmlview_primary_button.xmlactivity_main.xml7.2 布局 XML 的编排规范如果不确定布局文件如何排版可遵循以下约定每行一个属性缩进 4 个空格始终把android:id放在第一个属性android:layout_****类属性置于顶部style属性放在最后自闭合标签/独占一行便于排序与追加属性不要硬编码android:text考虑使用 Android Studio 提供的 Designtime 属性设计期预览专用。示例?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:toolshttp://schemas.android.com/tools android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical TextView android:idid/name android:layout_widthmatch_parent android:layout_heightwrap_content android:layout_alignParentRighttrue android:textstring/name stylestyle/FancyText / include layoutlayout/reusable_part / /LinearLayout黄金法则android:layout_****属性定位、外边距、尺寸等布局属性应留在布局 XML 中而其余android:****外观属性颜色、内边距、字体等应放进样式文件。存在以下例外android:id显然应留在布局文件LinearLayout的android:orientation通常放在布局文件中更合理android:text定义内容应放在布局文件有时把通用的android:layout_width/android:layout_height抽成样式是合理的但默认仍应写在布局文件里。7.3 使用样式styles消除重复属性几乎所有项目都需要恰当使用样式因为 View 的外观复用极为常见。至少应为应用中的大部分文本定义一个通用样式例如style nameContentText item nameandroid:textSizedimen/font_normal/item item nameandroid:textColorcolor/basic_black/item /style并应用到 TextViewTextView android:layout_widthwrap_content android:layout_heightwrap_content android:textstring/price stylestyle/ContentText /按钮通常也需要同样的处理但不要止步于此把一组重复且相关的android:****属性迁移到公共样式。7.4 拆分大样式文件没有必要只用一个styles.xml。Android SDK 原生支持任意文件名styles这个名字并无特殊魔法真正起作用的是文件内部的styleXML 标签。因此你可以拥有styles.xml、styles_home.xml、styles_item_details.xml、styles_forms.xml等多个文件。与资源目录名对构建系统有意义不同res/values下的文件名可以是任意的。7.5colors.xml只做一件事定义调色板colors.xml中除了颜色名 → RGBA 值的映射外不应再有任何别的内容。这样既能避免 RGBA 值被反复书写也让应用到底用了多少种颜色一目了然方便日后变更与重构对美观的 UI 而言收敛颜色种类本身就很重要。不要这样定义把业务语义揉进颜色名resources color namebutton_foreground#FFFFFF/color color namebutton_background#2A91BD/color color namecomment_background_inactive#5F5F5F/color color namecomment_background_active#939393/color color namecomment_foreground#FFFFFF/color color namecomment_foreground_important#FF9D2F/color ... color namecomment_shadow#323232/color这样极易重复 RGBA 值而且buttoncomment这类带上下文的定义本应放进按钮/注释的样式文件而不是colors.xml。应该这样定义纯调色板resources !-- Escala de grises灰度 -- color namewhite #FFFFFF/color color namegray_light#DBDBDB/color color namegray #939393/color color namegray_dark #5F5F5F/color color nameblack #323232/color !-- Colores básicos基础色 -- color namegreen#27D34D/color color nameblue#2A91BD/color color nameorange#FF9D2F/color color namered#FF432F/color /resources可以请应用的设计师来定这套调色板命名不必是greenblue这类直白颜色名color_primario主色、color_secundario次色之类的语义名同样很好。英文版 README.md 还进一步示范了三层职责划分colors.xml只定义调色板styles.xml中通过引用调色板来表达颜色用途如按钮前景为白色activity_main.xml引用样式给按钮上色若需要更彻底的解耦还可以再建一个引用调色板的中间颜色资源文件color namebutton_foregroundcolor/white/color color namebutton_backgroundcolor/blue/colorstyle nameAcceptButton item nameandroid:foregroundcolor/button_foreground/item item nameandroid:backgroundcolor/button_background/item /style这种做法的收益是更强的颜色重构能力与更稳定的样式定义代价是需要额外维护一组颜色映射。7.6dimens.xml同样做成尺寸调色板与colors.xml同理应对典型字号与间距定义一套调色板。一份好的 dimens 文件示例resources !-- Tamaño de letra字号 -- dimen namefont_larger22sp/dimen dimen namefont_large18sp/dimen dimen namefont_normal15sp/dimen dimen namefont_small12sp/dimen !-- Espacio entre dos Views视图间典型间距 -- dimen namespacing_huge40dp/dimen dimen namespacing_large24dp/dimen dimen namespacing_normal14dp/dimen dimen namespacing_small10dp/dimen dimen namespacing_tiny4dp/dimen !-- Tamaño de una View视图典型尺寸 -- dimen namebutton_height_tall60dp/dimen dimen namebutton_height_normal40dp/dimen dimen namebutton_height_short32dp/dimen /resources布局中的 margin 与 padding 应尽量使用spacing_****尺寸而非硬编码数值——就像字符串通常的处理方式一样。这能让应用获得一致的视觉体验也让样式与布局的调整更加容易。7.7strings.xml命名与大小写字符串的 key 应体现上下文namespace不必害怕两个或多个 key 共用同一个值语言是复杂的命名空间式的 key 能带来语境、消解歧义。不好key 语义模糊string namenetwork_errorNetwork error/string string namecall_failedCall failed/string string namemap_failedMap loading failed/string好key 携带上下文前缀string nameerror_message_networkNetwork error/string string nameerror_message_callCall failed/string string nameerror_message_mapMap loading failed/string不要用全大写书写字符串值遵循常规文本习惯例如仅首字母大写。如果确实需要全大写展示请在 TextView 上使用textAllCaps属性来实现不好string nameerror_message_callCALL FAILED/string好string nameerror_message_callCall failed/string八、避免过深的 ViewGroup 层级为了完成某种视图排布你可能忍不住再套一层 LinearLayout于是出现类似下面这种逐层嵌套LinearLayout android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical RelativeLayout ... LinearLayout ... LinearLayout ... LinearLayout ... /LinearLayout /LinearLayout /LinearLayout /RelativeLayout /LinearLayout即便单个布局文件中没有显式出现这种结构通过 Java 代码向其他 View 中 inflate 视图也可能在运行时形成同样的深树。深层级会带来两类问题一是性能问题——处理器需要维护一棵复杂 UI 树二是更严重的隐患——视图过多时可能触发StackOverflowError。因此应尽量让视图层级保持扁平学习使用 RelativeLayout、学会优化布局、善用merge标签。英文版 README.md 在此基础上进一步推荐了 ConstraintLayout它是构建扁平层级的有力工具。九、WebViews 的注意事项需要展示网页例如新闻正文时避免在客户端做 HTML 清洗处理——应要求后端返回纯净的 HTML。WebView 还有一个典型的内存泄漏点当它持有 Activity 的引用、而不是绑定到 ApplicationContext 时就会泄漏内存。此外简单文本或按钮不要用 WebView优先使用平台自带的 TextView 或 Button。十、测试框架、模拟器与调试工具10.1 测试框架该文档写作时的观点西语版如下Android SDK 自带的测试工具尚显稚嫩尤其 UI 测试方面。Android Gradle 提供了connectedAndroidTest任务借助 JUnit 的 Android 扩展运行单元测试这意味着需要连接真机或模拟器才能执行测试。Robolectric 只适合做单元测试不适合测视图它以无需连接设备换取开发速度适合 Models 与 View Models 的单元测试但它对 Android 平台的模拟实现并不精确也不完整动画、对话框等 UI 元素难以测试且测试是在盲测状态下进行的。Robotium 让 UI 测试编写更简单虽然不强制需要但它提供的视图查找/分析辅助与屏幕控制能力很有价值。测试用例可以简洁到这种程度solo.sendKey(Solo.MENU); solo.clickOnText(More); // 找到第一处 More 并点击 solo.clickOnText(Preferences); solo.clickOnText(Edit File Extensions); Assert.assertTrue(solo.searchText(rtf));版本演进提示仓库英文版 README.md 的测试主张已更新为——用 JUnit 做纯 JVM 上的无 Android 依赖单元测试、避免 Robolectric因其平台模拟不保证正确性建议改为 JVM 单元测试 真机集成测试的组合、用 Espresso 编写 UI 测试、用 AssertJ-Android 简化 Android 组件Support、Google Play Services、AppCompat 等的断言。断言示例// 使用 AssertJ-Android 的断言示例 assertThat(layout).isVisible() .isVertical() .hasChildCount(5);10.2 模拟器该文档当时的建议西语版是若以 Android 开发为职业购买 Genymotion 模拟器许可证——其帧率远高于典型 AVD 模拟器提供演示、网络质量模拟、GPS 定位等工具非常适合测试覆盖众多但非全部设备比购买多台真机划算得多。注意事项Genymotion 不含全部 Google 服务如 Google Play Store、Google Maps且三星特定 API 仍需真机验证。版本演进提示英文版 README.md 指出Android SDK 模拟器尤其 x86 变体性能近年已大幅改善、足以应付日常开发同时强调真机验证的价值并建议把测试精力聚焦于市场份额大、与产品最相关的设备。10.3 Stetho把 Chrome DevTools 变成 Android 调试台Stetho 是 Facebook 出品的 Android 调试桥与 Chrome 桌面浏览器的 Developer Tools 深度集成。通过它你可以轻松检查应用尤其是网络流量还能直接查看与编辑 SQLite 数据库和 SharedPreferences。务必确保 Stetho只在 debug 构建中启用绝不能进入 release 构建。英文版还提到备选方案 Chuck功能更简化但日志直接显示在设备上便于测试人员使用无需连接 Chrome。10.4 LeakCanary把内存泄漏检测变成日常LeakCanary 让内存泄漏的运行时检测与定位成为开发流程的常规一环。配置与用法详见其官方 wiki。关键提醒release 构建中只配置 no-op 依赖即空实现避免把检测逻辑带进生产包。十一、ProGuard 配置与混淆问题排查ProGuard 常用于 Android 项目对打包代码进行缩减shrink与混淆obfuscate。是否启用取决于项目配置常见做法是让 Gradle 只在构建 release APK 时启用buildTypes { debug { minifyEnabled false } release { signingConfig signingConfigs.release minifyEnabled true proguardFiles getDefaultProguardFile(proguard-android.txt), proguard-rules.pro } }要判断哪些代码必须保留、哪些可以丢弃或混淆需要为代码指定一个或多个入口点——通常是带有 main 方法的类、applet、midlet、Activity 等。Android 框架自带一份默认配置位于SDK_HOME/tools/proguard/proguard-android.txt上述配置中项目自定义的规则文件my-project/app/proguard-rules.pro会被追加到默认配置之后。11.1 经典问题构建成功却启动崩溃常见现象assembleRelease等构建命令无警告地成功了但应用启动即崩抛出ClassNotFoundException、NoSuchFieldException等异常。原因不外乎两种ProGuard 判定某类、枚举、方法、字段或注解不再需要将其移除ProGuard 对类、枚举或字段名做了混淆重命名但代码仍通过原名间接使用它例如 Java 反射。排查步骤检查app/build/outputs/proguard/release/usage.txt确认目标对象是否被移除检查app/build/outputs/proguard/release/mapping.txt确认目标对象是否被混淆。11.2 用 keep / keepnames 保护代码防止 ProGuard 移除所需类或成员在 ProGuard 配置中加入keep-keep class com.futurice.project.MyClass { *; }防止 ProGuard 混淆类或成员使用keepnames-keepnames class com.futurice.project.MyClass { *; }更多示例可参考 ProGuard 官方手册的 examples 章节。11.3 实战纪律项目早期就做 release 构建验证 ProGuard 规则是否正确保留了依赖。每引入新库或更新依赖后再做一次 release 构建并在真机上测试 APK。不要等到应用做到 1.0 版才首次做 release 构建——届时可能遭遇一堆意外与极短的修复时间。保留每次发布的mapping.txt这样当用户遇到 bug 并提交混淆后的堆栈轨迹时你才能据其定位与反解问题。DexGuard若需要更硬核的优化尤其是混淆能力可考虑 DexGuard——由开发 ProGuard 的同一团队出品的商业软件它还能轻松拆分 dex 文件以解决 65k 方法数限制。十二、数据存储SharedPreferences、ContentProviders 与 ORM12.1 SharedPreferences如果只需要持久化简单值、且应用运行在单一进程中SharedPreferences 是很好的默认选择。以下场景它并不适用性能数据复杂或数据量很大多进程访问有 widget 或远程服务运行在各自进程中、需要同步数据。英文版 README.md 还补充了第三种场景——关系型数据数据各部分之间存在关联、需要强制维护这些关系。也可以把复杂对象序列化为 JSON 存储、读取时再反序列化但要注意这种做法的性能与可维护性权衡。12.2 ContentProviders当 SharedPreferences 不够用时应使用平台标准的 ContentProviders——更快且进程安全。它唯一的缺点是搭建所需样板代码较多、且高质量教程稀缺。不过可以通过 Schematic 之类的库自动生成 ContentProvider显著降低工作量。之后仍需自己编写少量解析代码来读写 SQLite 列与数据对象之间的映射。也可以借助 Gson 等把数据对象序列化只持久化结果字符串——代价是性能损失好处是不必为类的每个字段声明一列。12.3 关于 ORM除非数据极端复杂且有迫切需求一般不推荐使用对象关系映射ORM库它们往往复杂、学习成本高。如果决定使用 ORM务必确认其是否进程安全如果应用有此需求的话——很多现有 ORM 方案在这方面出人意料地并不可靠。十三、持续集成CI英文版 README.md 进一步补充了持续集成主张CI 系统能在每次向版本控制推送更新时自动构建与测试项目还能运行静态代码分析、生成并分发 APK。Lint 与 Checkstyle 保障代码质量FindBugs 则在代码中寻找 bug。CI 软件种类繁多、特性各异开源项目通常可免费使用Jenkins 适合自建本地服务器Travis CI 则是云托管 CI 的推荐选择。这与本文开头构建过程由 Gradle 文件定义、而非 IDE 配置的原则一脉相承——只有可脚本化、可复现的构建才能被 CI 顺利接管。十四、结语与许可本文所依据的规范文档源自 Futurice 的实践沉淀仓库内提供 README.md 及各语言译本中文、西语、法语、日语、韩语、葡萄牙语、俄语、土耳其语、越南语全文遵循 Creative Commons Attribution 4.0 International (CC BY 4.0) 协议LICENSE可在注明出处的前提下自由使用与演绎。文中大部分代码示例、目录结构与命令均可直接对照仓库原文复现建议团队将其裁剪为本项目的工程规范并纳入代码评审清单。赞分享文档教程移动开发【免费下载链接】android-best-practicesDos and Donts for Android development, by Futurice developers项目地址https://gitcode.com/gh_mirrors/an/android-best-practices点击查看免费下载相关推荐oh-my-hermes技能体检omh-skill-health如何守护124个技能的质量oh my hermes技能体检omh skill health如何守护124个技能的质量 oh my hermesohm 是 Hermes Agent文档教程移动开发iOS开发最佳实践指南Futurice的完整入门指南iOS开发最佳实践指南Futurice的完整入门指南 本文详细介绍了iOS开发环境的搭建与配置、项目初始化与架构选择策略、依赖管理工具对比以及Git版本控制的文档教程RedwoodJS最佳实践指南如何构建可扩展的全栈项目结构RedwoodJS最佳实践指南如何构建可扩展的全栈项目结构 RedwoodJS是一个强大的全栈Web框架专为帮助开发者从 原型项目快速成长到创业级应用 而设后端前端Web框架开发工具上一篇Home Assistant IMAP 集成 imap.fetch_part 动作详解提取邮件附件与 MIME 部件下一篇DataHub Prefect 集成实战指南用 prefect-datahub Block 捕获 Flow/Task 血缘与运行元数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →