第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流程:

  1. 代码push到develop分支
  2. 触发GitHub Actions,运行./gradlew lint检查代码规范
  3. 运行./gradlew test跑单元测试
  4. 运行./gradlew assembleDebug打Debug包
  5. 上传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 知识体系总览

下面这张图,是我做项目时贴在墙上的。每次开工前看一眼,心里就有底了。

仿微信/抖音项目架构总览 :app 主工程 :feature:video :feature:chat :feature:user :feature:push :core:network | :core:common | :core:router | :core:database ViewModel | LiveData | Room | Retrofit | Hilt | Coil Git Flow | GitHub Actions | 自动化测试 | 持续部署

注意:模块化不是越细越好。我见过有人把每个工具类都拆成一个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