第30章 项目实战:仿微信/抖音核心功能、项目架构搭建(MVVM+Jetpack)、模块化开发、CI/CD持续集成、Git版本控制与协作
终于到了最后一章。说实话,每次带团队做项目,我都会把这一整套流程拿出来反复讲。为什么?因为光会写代码远远不够,你得让代码能跑、能维护、能协作。今天咱们就把仿微信/抖音这种级别的项目,从架构到发布,完整过一遍。
30.1 项目架构:MVVM + Jetpack 全家桶
我个人习惯,新项目起步第一件事就是搭架构。MVVM配上Jetpack,说白了就是让代码各司其职,别搅在一起。
核心分层:
- View层:Activity/Fragment,只负责UI展示和事件绑定
- ViewModel层:持有LiveData/StateFlow,处理业务逻辑
- Model层:Repository + 数据源(本地/远程)
举个例子,仿微信的聊天列表:
// ChatListViewModel.kt
class ChatListViewModel(
private val repository: ChatRepository
) : ViewModel() {
private val _chatList = MutableLiveData<List<ChatItem>>()
val chatList: LiveData<List<ChatItem>> get() = _chatList
fun loadChatList() {
viewModelScope.launch {
val result = repository.getChatList()
_chatList.value = result
}
}
}
我在项目中遇到过一个问题:ViewModel里直接调用网络请求,结果Activity重建时数据丢了。后来用了SavedStateHandle才搞定。嗯,这里要注意——ViewModel的生命周期比Activity长,但进程被杀还是会丢,所以关键数据要持久化。
30.2 模块化开发:别把所有代码塞在一个module里
你想想看,一个仿抖音的项目,有视频播放、用户系统、消息推送、直播……全写在一个app module里,那维护起来得多痛苦?
我建议这样拆分:
| 模块名 | 职责 | 依赖 |
|---|---|---|
| :app | 主工程,组装所有模块 | 所有业务模块 |
| :core:network | 网络请求封装(Retrofit) | 无 |
| :core:common | 工具类、基类、常量 | 无 |
| :feature:video | 视频播放、录制、编辑 | :core:network, :core:common |
| :feature:chat | 即时通讯、消息列表 | :core:network, :core:common |
| :feature:user | 个人中心、登录注册 | :core:network, :core:common |
模块化有个坑——依赖关系搞成循环了。我曾经因为:feature:video引用了:feature:user,而:feature:user又引用了:feature:video,编译直接报错。解决办法:抽一个:core:router模块,用ARouter或自己写路由表来解耦。
30.3 CI/CD 持续集成:让机器替你干活
每次提交代码都要手动打包、测试、部署?太累了。我团队现在用GitHub Actions,push到特定分支就自动触发流水线。
一个典型的CI流程:
- 代码push到
develop分支 - 触发GitHub Actions,运行
./gradlew lint检查代码规范 - 运行
./gradlew test跑单元测试 - 运行
./gradlew assembleDebug打Debug包 - 上传APK到内部测试平台(比如蒲公英)
# .github/workflows/android-ci.yml
name: Android CI
on:
push:
branches: [ develop ]
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: Lint check
run: ./gradlew lint
- name: Run tests
run: ./gradlew test
- name: Build debug APK
run: ./gradlew assembleDebug
- name: Upload APK
uses: actions/upload-artifact@v3
with:
name: app-debug
path: app/build/outputs/apk/debug/
小技巧:CI环境里不要用./gradlew默认的Gradle wrapper,建议用Gradle Build Cache,能省一半编译时间。
30.4 Git 版本控制与协作:别让代码冲突毁了你的一天
Git这东西,用好了是神器,用不好是噩梦。我见过最惨的一次,两个同事同时改了同一个文件,合并时冲突了200多行……
我的建议:
- 分支策略:
main(生产)、develop(开发)、feature/xxx(功能分支)、hotfix/xxx(紧急修复) - 提交规范:
feat: 新增视频录制功能、fix: 修复聊天列表闪退、refactor: 重构网络层 - Code Review:每个PR至少两个人Review,别自己合并自己的代码
我曾经犯过一个错:直接在main分支上改代码,结果上线前发现有个bug,回退都来不及。从那以后,我规定main分支只能通过PR合并,而且必须经过CI验证。
30.5 知识体系总览
下面这张图,是我做项目时贴在墙上的。每次开工前看一眼,心里就有底了。
注意:模块化不是越细越好。我见过有人把每个工具类都拆成一个module,结果编译时间从3分钟变成15分钟。合理粒度是:一个业务模块至少包含5个以上文件,否则不值得拆。
30.6 避坑指南:我踩过的那些坑
最后分享几个实战中容易翻车的地方:
- LiveData事件丢失:快速点击按钮触发两次网络请求,第二次的LiveData可能被覆盖。解决方案:用
SingleLiveEvent或者Kotlin Flow的SharedFlow。 - 模块间通信:别用接口回调跨模块,容易内存泄漏。我后来统一用EventBus + 路由,清爽多了。
- CI环境中文乱码:GitHub Actions的Ubuntu镜像默认没有中文字体,跑UI测试时截图全是方块。记得在
build.gradle里配置tasks.withType(Test) { systemProperty "file.encoding", "UTF-8" }。 - Git大文件:有人把APK、视频素材直接提交到Git仓库,导致clone速度慢到崩溃。用
.gitignore过滤掉*.apk、*.mp4,大文件走Git LFS。
好了,这一章的内容就到这里。项目实战不是一蹴而就的事,架构、模块化、CI/CD、Git协作,每一项都值得你花时间去打磨。希望这些经验能帮你少走弯路。
公众号:蓝海资料掘金营,微信deep3321