第三十章:Jetpack综合实战二:性能优化、测试策略、发布流程、持续集成、总结回顾、实战:完整项目发布
好,终于到了最后一章。说实话,写到这里我还有点不舍。不过该来的总会来,这一章我们不讲新组件,而是把前面学过的所有东西串起来,走一遍完整的项目发布流程。
你可能会问:「性能优化和测试,真的有那么重要吗?」
嗯,我在早期带团队时吃过亏。一个功能开发完就急着上线,结果用户反馈卡顿、崩溃,最后不得不紧急回滚。从那以后,我养成了一个习惯:没有经过性能验证和测试覆盖的代码,绝不进发布分支。
30.1 性能优化:不只是跑得快
性能优化这件事,说白了就是「让用户觉得爽」。我见过太多项目,功能做得很全,但滑动列表掉帧、页面打开慢半拍,用户直接就卸载了。
30.1.1 启动优化
应用启动是用户的第一印象。我个人习惯用 Startup 库来管理初始化任务,而不是一股脑全塞在 Application 里。
// 使用 Startup 库按需初始化
class MyInitializer : Initializer<Unit> {
override fun create(context: Context) {
// 只在需要时初始化
Log.d("Startup", "按需初始化完成")
}
override fun dependencies(): List<Class<out Initializer<*>>> {
return emptyList()
}
}
adb shell am start -W 包名/Activity 测量冷启动时间。如果超过 2 秒,就得排查了。
30.1.2 内存与布局优化
内存泄漏是性能杀手。我曾经在一个项目中,因为 Fragment 没在 onDestroy 里释放监听器,导致内存暴涨。后来我强制团队使用 LeakCanary,问题才彻底解决。
布局方面,我建议多用 ConstraintLayout 减少嵌套。你想想看,一个界面嵌套五六层 LinearLayout,GPU 渲染压力能不大吗?
// 使用 Profile GPU Rendering 工具
// 在开发者选项中开启,观察柱状图是否超过绿线
30.1.3 网络与数据缓存
网络请求是另一个重灾区。我习惯用 Room 做本地缓存,配合 WorkManager 做后台同步。这样即使用户断网,也能看到历史数据。
30.2 测试策略:别等上线才发现问题
测试这件事,我把它分成三层:单元测试、集成测试、UI 测试。每一层都有它的价值,缺一不可。
30.2.1 单元测试
单元测试测的是「最小单元」的逻辑。比如 ViewModel 里的数据转换、Repository 里的缓存策略。我用 JUnit + Mockito 来写。
@Test
fun testUserRepository_cacheFirst() {
val mockApi = mock(UserApi::class.java)
val repo = UserRepository(mockApi)
// 模拟网络异常,验证是否返回缓存
`when`(mockApi.fetchUser()).thenThrow(IOException())
val result = repo.getUser()
assertNotNull(result)
}
30.2.2 集成测试
集成测试测的是「组件之间的协作」。比如 Room 数据库的 DAO 操作、Navigation 的页面跳转。我用 AndroidX Test 来跑。
@RunWith(AndroidJUnit4::class)
class UserDaoTest {
@get:Rule
val dbRule = InstantTaskExecutorRule()
@Test
fun testInsertAndQuery() {
val db = Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
AppDatabase::class.java
).build()
db.userDao().insert(User(1, "测试用户"))
val user = db.userDao().getUser(1)
assertEquals("测试用户", user.name)
}
}
30.2.3 UI 测试
UI 测试我用 Espresso。说实话,写 UI 测试挺烦的,但每次上线前跑一遍,能发现很多肉眼看不到的问题。
@Test
fun testLoginButton() {
onView(withId(R.id.btn_login))
.perform(click())
onView(withText("登录成功"))
.check(matches(isDisplayed()))
}
30.3 发布流程:从代码到用户
发布流程我总结为三步:构建、签名、分发。每一步都有坑,我一个个说。
30.3.1 构建配置
用 Gradle 配置不同的构建类型。我习惯分 debug、release、staging 三种。
android {
buildTypes {
debug {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
}
staging {
initWith debug
applicationIdSuffix ".staging"
}
}
}
30.3.2 签名与加固
签名文件一定要保管好。我曾经有个同事把 keystore 放到了 Git 仓库里,结果被安全团队通报批评。现在我都用环境变量来管理密码。
// 在 gradle.properties 中引用环境变量
storePassword = System.getenv("KEYSTORE_PASSWORD")
keyPassword = System.getenv("KEY_PASSWORD")
30.3.3 分发渠道
我一般用 Firebase App Distribution 做内测,Google Play 做正式发布。内测版本要打上「测试版」的标识,避免用户混淆。
30.4 持续集成:自动化一切
持续集成(CI)是我最推崇的工程实践。说白了,就是让机器帮你做重复劳动。我用 GitHub Actions 来做。
30.4.1 配置 CI 流水线
name: Android CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
- name: Build with Gradle
run: ./gradlew assembleRelease
- name: Run tests
run: ./gradlew test
30.4.2 自动化测试与报告
CI 跑完后,我会自动生成测试报告,并发送到团队群里。这样谁写的测试挂了,一目了然。
30.5 总结回顾:这 30 章我们学了什么
回顾整个课程,我们从 Jetpack 的基础组件开始,一路走到架构设计、性能优化、测试和发布。你想想看,是不是已经能独立搭建一个完整的 Android 项目了?
我整理了一张知识体系图,帮你把零散的知识点串起来。
30.6 实战:完整项目发布
理论说再多,不如动手做一遍。下面我带你走一遍完整项目发布的流程。
30.6.1 项目结构
我习惯用多模块结构。每个模块职责单一,方便测试和复用。
app/
├── app/ # 主模块
├── core/ # 核心工具
├── data/ # 数据层
├── domain/ # 业务逻辑
├── feature/ # 功能模块
│ ├── login/
│ ├── home/
│ └── profile/
└── build.gradle.kts # 根配置
30.6.2 发布前检查清单
| 检查项 | 说明 | 工具/方法 |
|---|---|---|
| 性能测试 | 启动时间、内存占用、帧率 | Profiler / Perfetto |
| 测试覆盖 | 核心逻辑单元测试通过 | JUnit / Mockito |
| 代码规范 | Lint 无严重错误 | ./gradlew lint |
| 签名配置 | Release 签名正确 | 检查 keystore |
| 版本号 | versionCode 递增 | Gradle 配置 |
30.6.3 执行发布
一切检查无误后,执行以下命令:
# 清理构建
./gradlew clean
# 构建 Release 包
./gradlew assembleRelease
# 运行所有测试
./gradlew test
# 生成测试报告
./gradlew jacocoTestReport
好了,整个课程到这里就结束了。从第一章的 Jetpack 基础,到最后一章的完整发布,你跟着我一步步走完了 Android 开发的完整链路。说实话,能坚持看到这里,你已经比大多数开发者强了。
以后在项目中遇到问题,记得回来翻翻这些章节。代码是死的,但思路是活的。希望这些经验能帮你少踩一些坑,多做一些好产品。
加油,未来的架构师。