—— Android 平台开发知识培训 · 从系统到上架 ——

Android 的修炼之道

小哲的公司决定做「轻记账」的原生 Android App——他刚在《JavaSE 到 JavaEE》里学完 Java,正好用上。但移动开发和后端是两套世界:Activity 生命周期、Kotlin 协程、Jetpack Compose、上架审核……周师傅说:Android 是「一个系统 + 一套组件 + 一堆规矩」的江湖,十站带你入门到上架。

🤖 🧱 💬 🖥️ 🌐 🏗️ 🔀 📦 🧪 🛡️ 🚀
序 章

移动端的入场券

Android 开发全景:语言 + 系统 + 组件 + 工程
🧑‍💻
小哲

师傅!公司要做「轻记账」的原生 Android App——我刚学完 Java,是不是直接就能上手了?

🧙
周师傅

Java 是「一半」——现代 Android 的主力语言是 Kotlin(和 Java 无缝互通,你学过的 Java 语法和面向对象完全用得上)。但真正的门槛不是语言,而是「平台」:

  • 系统层:App 跑在 Linux 内核 + ART 运行时上——进程模型和桌面端完全不同。
  • 组件层:四大组件(Activity/Service/广播/ContentProvider)——App 的骨架。
  • UI 层:Jetpack Compose(声明式 UI)——现代写法。
  • 工程层:Gradle 构建、签名、上架、适配——移动开发的「规矩」特别多。

来,十站路线——

1
系统架构Linux 内核、ART、进程模型——App 跑在哪
2
Kotlin 语言空安全、扩展函数、协程、data class——现代语言
3
四大组件Activity/Service/广播/ContentProvider + 生命周期
4
UI 开发Jetpack Compose、声明式 UI、Material Design
5
数据层Retrofit/OkHttp、Room、DataStore——网络与存储
6
Jetpack 架构ViewModel、Flow、Repository、MVVM、Hilt
7
协程Dispatchers、结构化并发、Flow——异步不卡 UI
8
工程化Gradle、模块化、签名、多渠道、上架流程
9
测试质量单元/UI 测试、ANR、启动优化、崩溃监控
10
安全适配运行时权限、版本碎片化、隐私合规
🧙
周师傅

记住一句话:Android 开发 = 懂系统(进程/生命周期)+ 会组件(四大件)+ 写 UI(Compose)+ 守规矩(适配/权限/合规)。走,第一站,先看 App 跑在什么上面。

第 1 站

系统架构:平台怎么组织

Linux 内核 · ART · 进程模型 · 系统服务

桌面程序想开就开、想关就关;Android App 的「生死」却是系统说了算——不了解平台架构,你就理解不了为什么 Activity 要「保存状态」、为什么内存会被回收。

🧙
周师傅

Android 平台四层架构:

  • Linux 内核:地基——进程管理、内存管理、驱动(和第十五本爬虫无关,和服务器 Linux 是亲戚)。
  • 系统服务层:AMS(Activity 管理)、WMS(窗口管理)、PackageManager 等——App 和系统打交道的「窗口」。
  • ART 运行时:App 代码的「执行引擎」——Kotlin/Java 编译成字节码,ART 负责跑(JIT+AOT,第十四本 JVM 的移动版)。
  • 应用框架层:四大组件 + Jetpack 库——开发者直接用的 API。

关键认知:每个 App 跑在自己的进程 + 沙箱里——App 间默认隔离(安全基础);系统内存不足时按优先级杀 App 进程(后台的优先被杀)。

Android 平台架构图
┌──────────────────────────────────┐
│ 应用层:你的 App(四大组件)        │ ← 开发者在这里
│ Jetpack 库(ViewModel/Compose…)  │
├──────────────────────────────────┤
│ 应用框架层:AMS/WMS/ContentProvider│ ← 系统服务
├──────────────────────────────────┤
│ 系统运行库:ART(执行引擎)        │ ← Kotlin/Java 字节码在这跑
│        + 原生库(C/C++)          │
├──────────────────────────────────┤
│ Linux 内核:进程/内存/驱动         │ ← 地基
└──────────────────────────────────┘

【进程与沙箱(移动端和桌面最大的不同)】
  每个 App 一个进程 + 独立沙箱(互相隔离)
  系统内存不足 → 杀后台进程(按优先级:前台>可见>服务>后台)
  → 所以 App 要「保存状态」:进程可能随时被回收!

【Android 版本碎片化(永恒的痛)】
  系统版本多(Android 8~15+)、厂商定制多(MIUI/ColorOS…)
  → 适配是 Android 开发日常(第10站)

【ART vs JVM(第十四本对比)】
  桌面 Java:JVM 跑,一次编译到处运行
  Android:ART 跑,AOT 预编译到设备指令(更快启动)

【构建产物】
  .apk(安装包)/ .aab(上架用,Google Play 分包)

系统架构术语

  • Linux 内核 / 沙箱:地基 / 进程隔离——安全的基础。
  • ART 运行时:Android 的执行引擎——JIT+AOT 混合编译。
  • 系统服务:AMS / WMS——App 和系统的「窗口」。
  • 进程优先级:后台进程会被系统回收——状态保存的必要性。
  • apk / aab:安装包 / 上架分包格式。
  • 版本碎片化:多版本多厂商——Android 适配的宿命。

本站收获:平台认知 = 每个 App 一个沙箱进程 + ART 跑代码 + 系统按优先级杀进程 + 版本碎片化。理解了「进程会被杀」,就理解了 Android 一半的设计。

第 2 站

Kotlin:现代语言

空安全 · 扩展函数 · data class · 协程 · 与 Java 互通

Kotlin 是 Android 的「官方语言」——比 Java 更简洁、更安全(空指针不再是噩梦)。你有 Java 底子,学 Kotlin 就像「从手动挡换自动挡」。

🧙
周师傅

Kotlin 四大爽点:

  • 空安全:类型分「可空」和「不可空」(String vs String?)——编译器就拦住空指针(Java 的 NPE 噩梦拜拜)。
  • 扩展函数:给已有类「加方法」——`fun String.isPhone(): Boolean`——不用继承不用改源码。
  • data class:一行声明 + 自动生成 equals/hashCode/toString——Java 的 POJO 样板代码全没了。
  • 协程:轻量级并发——比线程轻得多(第 7 站主角);还有 lambda、作用域函数(let/apply/run)。

关键:Kotlin 和 Java 100% 互操作——你学的 Java 库(Retrofit 等)直接能用。

Kotlin vs Java(对照学)
// Java: 一个简单的类要写一大坨
// public class User { private String name; ... getter/setter ... }

// Kotlin: data class 一行搞定
data class User(
    val id: Long,
    val name: String,
    val phone: String?          // 可空类型:可能为 null
)

// 空安全:编译器强制处理 null
fun greet(user: User?) {
    println(user?.name ?: "匿名用户")    // 空安全调用 + 兜底
    // user!!.name  // 强制非空(危险,少用)
}

// 扩展函数:给 String 加方法
fun String.isValidPhone(): Boolean =
    length == 11 && startsWith("1")

// 作用域函数
val name = user?.let { it.name } ?: "unknown"   // let:非空才执行
user?.apply { /* 在对象上下文里操作 */ }

// lambda:函数式(第一本老朋友)
val adults = users.filter { it.age >= 18 }
                 .map { it.name }

【Kotlin 与 Java 关系】
  互操作:Kotlin 能调 Java 库,Java 也能调 Kotlin
  编译:都编译成 JVM 字节码(Android 上由 ART 执行)
  趋势:新项目 Kotlin 是默认,Java 老项目继续维护

【协程预告(第7站)】
  suspend fun fetchData() = withContext(Dispatchers.IO) { ... }
  → 挂起不阻塞,比线程轻 1000 倍

Kotlin 术语

  • 空安全(? 与 ?:):可空类型 + Elvis 运算符——NPE 从运行时移到编译期。
  • 扩展函数:给类加方法不继承——String.isValidPhone()。
  • data class:自动 equals/hashCode/toString——POJO 终结者。
  • 作用域函数:let / apply / run / with——简洁的上下文操作。
  • lambda / 函数式:filter/map——和 Python 同款思路。
  • 协程(suspend):轻量并发——Android 异步标准(第 7 站)。
  • 互操作:Kotlin ↔ Java 无缝——学过的 Java 全用得上。

本站收获:Kotlin = 空安全(NPE 绝迹)+ 扩展函数(简洁)+ data class(省代码)+ 协程(轻并发)。Java 底子 + Kotlin 语法 = Android 开发的语言准备完毕。

第 3 站

四大组件:应用骨架

Activity · Service · 广播 · ContentProvider · 生命周期

Android App 的「骨架」由四大组件搭成——每个组件都有自己的一套生命周期规则。搞懂它们,就搞懂了 App 的「活法」。

🧙
周师傅

四大组件各司其职:

  • Activity:一个「界面」——看得见的页面。生命周期是面试必考:onCreate(创建)→ onStart(可见)→ onResume(可交互)→ onPause(失去焦点)→ onStop(不可见)→ onDestroy(销毁)。
  • Service:后台任务——播放音乐、下载文件(没界面的活)。
  • BroadcastReceiver(广播):收「系统/应用消息」——开机、网络变化、电量低(系统事件的通知)。
  • ContentProvider(内容提供者):跨 App 共享数据——通讯录、相册就是这样开放的(注意权限)。

Intent 是组件间的「信使」——启动 Activity、发广播、起 Service 全靠它。

Activity 生命周期(面试必考图)
用户打开 App
   ↓
onCreate(创建:初始化 UI/数据)——只调一次
   ↓
onStart(可见:还没可交互)
   ↓
onResume(可交互:前台焦点)── 返回 ──┐
   ↓                                   │
onPause(失去焦点:弹窗/来电话)        │
   ↓                                   │
onStop(不可见:切后台)──────────────┤
   ↓                                   │
onDestroy(销毁:进程被回收/用户关闭)   │
   → 系统可能随时回收后台进程(第1站)────┘

【为什么生命周期重要】
  旋转屏幕 → Activity 销毁重建 → 数据要保存(onSaveInstanceState)
  切后台 → 音乐 Service 继续播(Service 的用武之地)
  内存不足 → 系统杀后台 → 回来要恢复状态

【Kotlin 实现(简化)】
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { ... }        // Compose UI(第4站)
    }
    override fun onSaveInstanceState(outState: Bundle) {
        outState.putString("note", currentNote)   // 保存状态
        super.onSaveInstanceState(outState)
    }
}

【Service 类型】
  前台服务(有通知,用户看得见——播放器)
  后台服务(WorkManager 管理——约束触发,现代推荐)

【Intent 三兄弟】
  显式 Intent:指定目标组件(App 内跳转)
  隐式 Intent:描述动作,系统匹配(打开网页/分享)
  PendingIntent:留待将来执行的 Intent(通知点击)

组件术语

  • Activity:界面 + 生命周期——App 的门面。
  • Service:后台任务——没界面的活。
  • BroadcastReceiver:系统/应用事件通知——广播消息。
  • ContentProvider:跨 App 数据共享——通讯录模式。
  • Intent:组件间的信使——显式/隐式。
  • 生命周期:onCreate → onResume → onPause → onDestroy——面试必背。
  • 状态保存:旋转/回收后的数据恢复——onSaveInstanceState。

本站收获:四大组件 = Activity(界面)+ Service(后台)+ 广播(通知)+ ContentProvider(共享),Intent 当信使。生命周期是 Android 的「宪法」——背熟它,就懂了一半 Android。

第 4 站

UI 开发:Jetpack Compose

声明式 UI · Composable · 状态驱动 · Material Design

老 Android 用 XML 布局 + findViewById;现代 Android 用 Jetpack Compose——声明式 UI,像写函数一样写界面,状态一变界面自动更新。

🧙
周师傅

Jetpack Compose 是 Android 的现代 UI 框架,核心思想:

  • 声明式:界面 = f(状态)——用 Kotlin 函数声明 UI,不用 XML 布局。
  • 状态驱动:状态(state)一变,用到的界面自动重组(recompose)——不用手动 findViewById + setText。
  • Composable 函数:`@Composable` 标注的可组合函数——界面的「积木」。
  • Material Design:官方设计语言——组件库现成(按钮/卡片/主题)。

列表用 LazyColumn(虚拟化,几十万条不卡);状态管理用 remember + mutableStateOf(局部)或 ViewModel(全局,第 6 站)。

Compose 声明式 UI 实战
@Composable
fun OrderListScreen(viewModel: OrderViewModel) {
    val orders by viewModel.orders.collectAsState()   // 状态订阅

    LazyColumn {                                      // 虚拟化列表
        items(orders) { order ->
            OrderCard(order)                          // 每行一个卡片
        }
    }
}

@Composable
fun OrderCard(order: Order) {
    Card(elevation = 4.dp, modifier = Modifier.padding(8.dp)) {
        Row(Modifier.padding(16.dp)) {
            Column(Modifier.weight(1f)) {
                Text(order.title, style = MaterialTheme.typography.titleMedium)
                Text("¥${order.amount}", color = MaterialTheme.colorScheme.primary)
            }
            Icon(Icons.Default.Add, contentDescription = null)
        }
    }
}

// 状态驱动:点一下按钮,界面自动更新
@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }      // 状态
    Button(onClick = { count++ }) {
        Text("点击了 $count 次")                       // 状态变 → 自动重组
    }
}

【Compose vs 老 View 体系】
  老(XML + findViewById):手动找控件、手动更新——代码多
  Compose:声明式函数 + 状态自动驱动——代码少、好维护
  → 新项目 Compose 是默认,老项目 View 继续维护

【UI 组件速查】
  布局:Column / Row / Box(线性/横向/层叠)
  常用:Text / Button / Card / Icon / Image
  列表:LazyColumn / LazyRow(虚拟化)
  主题:MaterialTheme(颜色/字体/形状统一)

UI 术语

  • Jetpack Compose:现代声明式 UI 框架——Android 的新默认。
  • Composable:@Composable 函数——界面的积木。
  • 状态驱动:mutableStateOf + 自动重组——UI 随状态变。
  • remember:记住状态——重组不丢数据。
  • LazyColumn:虚拟化列表——大数据量不卡。
  • Material Design:官方设计语言——主题/组件现成。
  • Modifier:布局修饰链——padding/weight/clickable。

本站收获:Compose = 声明式函数写界面 + 状态驱动自动更新 + LazyColumn 管列表。UI 从「手动档」变「自动档」——界面即函数,状态即真相。

第 5 站

数据层:网络与存储

Retrofit/OkHttp · Room · DataStore · 序列化

App 的数据从哪来?——网络(Retrofit 调后端)+ 本地(Room 存数据库)。这一站,移动端的数据层三件套。

🧙
周师傅

数据层四件套:

  • Retrofit + OkHttp:网络请求事实标准——接口声明成 Kotlin 函数,自动解析 JSON(第十六本 FastAPI 的客户端版)。
  • Room:SQLite 的官方 ORM——编译期校验 SQL、返回 Flow/协程结果(第十六本 SQLAlchemy 的 Android 版)。
  • DataStore:轻量键值存储——替代老 SharedPreferences(存设置/偏好)。
  • 序列化:kotlinx.serialization / Gson / Moshi——JSON ↔ 对象的互转。

架构模式:Repository(仓库)——统一数据入口,内部决定「先查缓存还是先查网络」(第 6 站 MVVM 的主角之一)。

Retrofit + Room 实战
// ① Retrofit:接口声明(自动发请求 + 解析 JSON)
interface LedgerApi {
    @GET("api/orders")
    suspend fun getOrders(): List<Order>      // 协程挂起函数

    @POST("api/orders")
    suspend fun createOrder(@Body order: Order): Order
}

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.ledger.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

// ② Room:本地数据库
@Entity
data class OrderEntity(
    @PrimaryKey val id: Long,
    val title: String,
    val amount: Double,
)

@Dao
interface OrderDao {
    @Query("SELECT * FROM orders")
    fun observeAll(): Flow<List<OrderEntity>>    // Flow 观察变化

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun upsert(orders: List<OrderEntity>)
}

// ③ Repository:统一数据入口(缓存优先)
class OrderRepository(
    private val api: LedgerApi,
    private val dao: OrderDao,
) {
    val orders: Flow<List<OrderEntity>> = dao.observeAll()

    suspend fun refresh() {
        val remote = api.getOrders()              // 拉网络
        dao.upsert(remote.map { it.toEntity() })  // 存本地
        // 界面观察 dao → 自动更新(缓存优先架构)
    }
}

【数据流设计】
  界面 → ViewModel → Repository → (网络/数据库)
  离线可用:先读 Room 缓存 → 后台刷新 → 界面自动更新
  → 和第十六本 Repository 模式一模一样!

数据层术语

  • Retrofit / OkHttp:网络请求标准——接口即函数。
  • Room(SQLite ORM):本地数据库——编译期校验 SQL。
  • DataStore:轻量存储——设置/偏好。
  • 序列化:Gson/Moshi/kotlinx——JSON 互转。
  • Repository 模式:统一数据入口——缓存优先。
  • Flow 观察:数据库变化自动推送——响应式 UI 的数据源。
  • 离线优先:本地缓存 + 后台刷新——弱网也流畅。

本站收获:数据层 = Retrofit 拉网络 + Room 存本地 + Repository 统一入口(缓存优先)。和第十六本后端的 Repository/MVVM 完全同构——移动端只是「多了一层本地缓存」。

第 6 站

Jetpack 架构:MVVM

ViewModel · Flow · MVVM · Hilt · WorkManager

App 的代码怎么组织才不乱?官方推荐 MVVM 架构——UI 和逻辑分离,配置变更(旋转屏幕)不丢数据,依赖注入自动管理。

🧙
周师傅

MVVM 四层(官方推荐架构):

  • UI 层:Compose 界面——只负责展示 + 转发用户操作(不写业务)。
  • ViewModel:持有状态 + 业务逻辑——配置变更/旋转屏幕时不销毁(Activity 没了它还活着)。
  • Repository:数据统一入口(第 5 站讲过)——网络/缓存的决策者。
  • 数据层:Retrofit / Room——最底层。

配套:Hilt(依赖注入——Dagger 的官方封装,自动提供对象,第十四本 Spring IoC 的 Android 版)和 WorkManager(后台任务——延迟/约束触发,系统帮忙调度)。

MVVM 架构落地(账小灵 App)
// ① UI 层:Compose 只做展示和转发
@Composable
fun OrderScreen(viewModel: OrderViewModel) {
    val uiState by viewModel.uiState.collectAsState()
    when (val s = uiState) {
        is Loading -> CircularProgressIndicator()
        is Success -> OrderList(s.orders, onRefresh = viewModel::refresh)
        is Error   -> Text("出错了:${s.message}")
    }
}

// ② ViewModel:状态 + 业务逻辑(旋转不销毁!)
class OrderViewModel(
    private val repo: OrderRepository,
) : ViewModel() {
    val uiState: StateFlow<UiState> = repo.orders
        .map { UiState.Success(it) }
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Loading)

    fun refresh() = viewModelScope.launch { repo.refresh() }
}

// ③ Hilt:依赖注入(不用手动 new!)
@HiltViewModel
class OrderViewModel @Inject constructor(
    private val repo: OrderRepository,
) : ViewModel()

【MVVM 数据流(单向)】
  用户操作 → ViewModel(改状态)→ UI 自动更新
  → 逻辑不写 UI 里、状态不散落在界面——好测、好维护

【为什么 ViewModel 重要】
  旋转屏幕 Activity 重建——ViewModel 存活,数据不丢
  进程被系统杀了(第1站)——ViewModel 也能配合 SavedState 恢复

【WorkManager 场景】
  上传日志(延迟+联网才跑)、每日提醒、数据库清理
  → 系统调度,省电,App 被杀也会补跑

架构术语

  • MVVM:UI + ViewModel + Repository + 数据层——官方推荐架构。
  • ViewModel:状态持有者——配置变更不销毁。
  • StateFlow / UiState:响应式状态流——UI 订阅自动更新。
  • Hilt:依赖注入——自动组装对象(Spring IoC 的 Android 版)。
  • WorkManager:后台任务调度——延迟/约束触发。
  • 单向数据流:UI → 逻辑 → 状态 → UI——清晰可测。
  • viewModelScope:ViewModel 的生命周期作用域——协程自动取消。

本站收获:MVVM = UI 只管显示 + ViewModel 管状态 + Repository 管数据 + Hilt 自动装配。和第十六本后端的分层思想一模一样——架构的尽头都是「职责分离」。

第 7 站

协程:异步与并发

Dispatchers · 结构化并发 · Flow · 挂起函数

网络请求不能在主线程跑(会卡 UI、甚至 ANR);也不能用「回调地狱」嵌套。Kotlin 协程给出优雅答案:像写同步代码一样写异步。

🧙
周师傅

协程三件套:

  • 挂起函数(suspend):可以「暂停」的函数——等网络时不阻塞线程,像同步代码一样写。
  • Dispatchers(调度器):决定代码跑在哪个线程——Main(UI 线程)/ IO(网络/数据库)/ Default(CPU 计算)。
  • 作用域(Scope):协程的生命周期容器——viewModelScope 等,页面销毁自动取消(防内存泄漏)。

进阶:Flow——响应式数据流(冷流:订阅才执行),Room 返回 Flow 实时推送数据库变化(第 5 站老朋友);structured concurrency——协程自动管理父子关系,异常不会静默。

协程实战:网络请求不卡 UI
// 错误示范:主线程发网络请求 → 卡死 + ANR!
// 正确姿势:挂起函数 + 切换调度器

class OrderRepository(private val api: LedgerApi) {

    // suspend:可挂起的网络请求(Retrofit 原生支持)
    suspend fun fetchOrders(): List<Order> =
        withContext(Dispatchers.IO) {        // IO 线程跑网络
            api.getOrders()
        }
}

// ViewModel 里调用(自动在主线程安全更新 UI)
class OrderViewModel(private val repo: OrderRepository) : ViewModel() {
    fun load() = viewModelScope.launch {    // 主线程作用域
        val orders = repo.fetchOrders()      // 自动切 IO,回来切 Main
        uiState.value = UiState.Success(orders)   // UI 更新安全
    }
}

// Flow:响应式数据流
val latestOrders: Flow<List<Order>> = flow {
    while (true) {
        emit(repo.fetchOrders())             // 每 30 秒发一次
        delay(30_000)
    }
}.flowOn(Dispatchers.IO)                     // 上游在 IO 跑

【协程 vs 线程(第十六本老朋友)】
  线程:重量级(1 个线程 ≈ 1MB 栈)——几万个就爆
  协程:轻量级(挂起不占线程)——几十万个都行
  → Android 默认用协程(asyncio 的 Kotlin 版)

【结构化并发】
  viewModelScope:界面销毁 → 协程自动取消 → 不泄漏
  SupervisorJob:子协程失败不影响兄弟

【ANR 预防】
  主线程只做 UI——超过 5 秒不响应 = ANR(第9站)

协程术语

  • suspend 挂起函数:可暂停的异步代码——像同步一样写。
  • Dispatchers:Main / IO / Default——线程调度器。
  • viewModelScope:生命周期作用域——自动取消防泄漏。
  • withContext:切换调度器——IO 干活、主线程更新。
  • Flow:响应式数据流——冷流订阅即执行。
  • 结构化并发:父子协程自动管理——异常不静默。
  • ANR:主线程卡 5 秒——应用无响应(第 9 站)。

本站收获:协程 = suspend 写异步 + Dispatchers 管线程 + Scope 管生命周期 + Flow 做响应式。Android 异步的标准答案——「挂起不阻塞,取消不漏泄」。

第 8 站

工程化:构建与上架

Gradle · AGP · 签名 · 多渠道 · 上架流程

代码写好了,怎么变成用户手机里的 App?Gradle 构建、签名、打包、上架审核——移动端的「最后一公里」全是规矩。

🧙
周师傅

工程化六件事:

  • Gradle + AGP:构建系统(第十六本 Maven/Gradle 的老朋友)——依赖管理 + 编译打包。
  • 模块化:app 模块 + 多个 library 模块(core/network/ui)——大型项目必备。
  • 签名:APK 必须有签名才能安装——密钥要保管好(丢了无法更新!)。
  • 多渠道打包:国内上架每个应用商店一个包(友盟/腾讯/华为...)——不同渠道号统计来源。
  • 混淆 / R8:代码压缩混淆——减小体积 + 防逆向(专业版加固)。
  • 上架流程:Google Play(aab 格式)/ 国内各商店——隐私政策、审核、更新。
构建与上架速览
【Gradle 配置(build.gradle.kts)】
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "com.ledger.app"
    compileSdk = 35                 // 编译版本(对应 Android 15)
    defaultConfig {
        applicationId = "com.ledger.app"
        minSdk = 24                 // 最低支持 Android 7.0
        targetSdk = 35              // 目标版本(上架要求新)
        versionCode = 12            // 版本号(更新递增)
        versionName = "2.1.0"       // 版本名(给用户看)
    }
    buildTypes {
        release {
            isMinifyEnabled = true  // R8 混淆压缩
        }
    }
}

【构建命令】
  ./gradlew assembleDebug     # 调试包(可直接安装)
  ./gradlew assembleRelease   # 发布包(签名+混淆)
  ./gradlew bundleRelease     # aab(Google Play 上架用)

【签名(保命)】
  生成:keytool / Android Studio 生成 keystore
  保管:丢了 = 以后无法更新同一个 App!
  国内商店要签名 + 部分要软著证书

【国内上架流程(简化)】
  准备:隐私政策 + 软著 + 应用截图 + 签名包
  提交各商店(华为/小米/OPPO/vivo/腾讯应用宝…)
  审核(隐私合规是重灾区,第10站)
  发布后:版本更新、崩溃监控(第9站)

【版本适配提示】
  targetSdk 必须跟随最新(商店强制要求)
  minSdk 决定覆盖多少设备(24 = 覆盖 95%+)

工程化术语

  • Gradle / AGP:构建系统——依赖 + 编译 + 打包。
  • minSdk / targetSdk / compileSdk:最低支持 / 目标版本 / 编译版本。
  • 签名(keystore):安装凭证——丢了无法更新。
  • R8 混淆:压缩 + 混淆——减小体积防逆向。
  • 多渠道打包:各商店独立包 + 渠道统计。
  • aab vs apk:Play 分包格式 vs 通用安装包。
  • 上架审核:隐私政策 + 合规是重灾区(第 10 站)。

本站收获:工程化 = Gradle 构建 + 模块化 + 签名保命 + 多渠道 + R8 混淆 + 上架审核。开发只是前半场,构建、签名、审核——移动端的规矩比后端多得多。

第 9 站

测试质量:让 App 稳

单元测试 · UI 测试 · ANR · 启动优化 · 崩溃监控

App 崩一次,用户流失一批。移动端的质量 = 测试 + 性能 + 监控三件套——这一站,让 App「稳」。

🧙
周师傅

质量三件套:

  • 测试:单元测试(JUnit + Mockito 测 ViewModel/业务,第十六本老朋友)+ UI 测试(Compose Test 点按钮断言界面)。
  • 性能ANR(主线程卡 5 秒——别在主线程干重活)、启动优化(冷启动 2 秒内)、内存泄漏(LeakCanary 检测)、帧率(掉帧卡顿)。
  • 监控崩溃监控(Crashlytics)——用户崩溃自动上报 + 堆栈分析;埋点——用户行为统计(第八本老朋友)。
测试与质量实战
// ① 单元测试:ViewModel 业务逻辑
@Test
fun `订单金额格式化正确`() {
    val vm = OrderViewModel(mockRepo)
    assertEquals("¥1,299.00", vm.formatAmount(1299.00))
}

// ② UI 测试(Compose Test)
@get:Rule
val composeRule = createComposeRule()

@Test
fun `点击按钮列表更新`() {
    composeRule.setContent { Counter() }
    composeRule.onNodeWithText("点击了 0 次").assertExists()
    composeRule.onNodeWithText("点击了 0 次").performClick()
    composeRule.onNodeWithText("点击了 1 次").assertExists()
}

【性能三巨头(移动端特有)】
  ANR:主线程 5 秒无响应 → 系统弹「应用无响应」
    预防:主线程只做 UI;重活走协程 IO(第7站)
  冷启动:点击图标到首帧——目标 < 2 秒
    优化:启动任务异步化、延迟初始化、启动页
  内存泄漏:Activity 被持有不释放 → OOM
    检测:LeakCanary 自动定位泄漏点

【崩溃监控(Crashlytics)】
  集成 SDK → 用户崩溃自动上报
  → 崩溃率看板 + 堆栈定位 + 版本对比
  → 发布后盯三天:崩溃率 > 0.5% 要紧急修复

【发布质量门槛】
  单元测试覆盖率 > 60%(核心逻辑 100%)
  无内存泄漏告警(LeakCanary 全绿)
  崩溃率 < 0.5%(新版本观察期)
  启动 < 2 秒 / 掉帧率 < 5%

质量术语

  • JUnit / Mockito:单元测试——测 ViewModel 逻辑。
  • Compose Test:UI 测试——点按钮断言界面。
  • ANR:主线程 5 秒无响应——移动端最著名的错误。
  • 冷启动优化:启动 < 2 秒——第一印象。
  • LeakCanary:内存泄漏自动检测——OOM 的克星。
  • Crashlytics:崩溃监控——用户崩溃自动上报。
  • 掉帧 / 帧率:60fps 目标——卡顿的可视化指标。

本站收获:质量 = 单测测逻辑 + UI 测交互 + ANR/泄漏/启动三座性能山 + Crashlytics 盯崩溃。移动端没有「重启一下」的机会——用户走了就不会回来。

第 10 站

安全适配:江湖规矩

运行时权限 · 版本适配 · 屏幕适配 · 隐私合规

Android 的「江湖规矩」特别多:权限要运行时申请、系统版本碎片化要适配、隐私合规是上架生死线。这一站,把规矩讲完。

🧙
周师傅

四大规矩:

  • 运行时权限:Android 6.0+ 权限「动态申请」——用到时弹窗问用户(相机/定位/通讯录);拒绝要优雅降级(第八本安全 + 第七本的老朋友)。
  • 版本适配:系统碎片化(Android 8~15+)+ 厂商定制——用兼容库(AndroidX/Jetpack)自动处理大部分差异;targetSdk 跟随最新(商店强制)。
  • 屏幕适配:手机/平板/折叠屏——用 dp 单位 + ConstraintLayout/Compose 自适应 + 多资源限定符。
  • 隐私合规个保法(第八本老朋友)——隐私政策、权限最小化、告知同意;国内商店审核重灾区:违规收集个人信息 = 下架。
安全适配要点速览
【运行时权限(Kotlin 简版)】
if (ContextCompat.checkSelfPermission(this, CAMERA) != GRANTED) {
    requestPermissions(arrayOf(CAMERA), 100)   // 弹窗申请
} else {
    openCamera()
}
// 用户拒绝 → 引导去设置页 / 功能降级(别硬来)

【版本适配策略】
  用 AndroidX/Jetpack 兼容库(自动处理 90% 差异)
  targetSdk 跟上最新(商店强制 + 新行为适配)
  老版本降级:功能检测(Build.VERSION.SDK_INT)按需分支

【屏幕适配】
  单位用 dp(密度无关)/ sp(文字)——别用 px!
  Compose 自适应布局(BoxWithConstraints / 窗口尺寸)
  多资源:values-sw600dp(平板)/ values-night(深色模式)

【隐私合规清单(上架生死线)】
  □ 隐私政策在应用内可查 + 首次弹窗告知
  □ 权限最小化(不申请用不到的权限!)
  □ 收集数据要「告知-同意」+ 提供删除渠道(第八本)
  □ 敏感权限(通讯录/位置)用途说明
  □ SDK 合规(第三方 SDK 也要审——不合规被通报)

【数据安全(第7本老朋友)】
  HTTPS 全链路(明文流量默认禁止)
  敏感数据加密存储(EncryptedSharedPreferences)
  WebView 安全(禁用 file 访问、白名单域名)
应用场景:上架被拒的「隐私整改」

轻记账提交应用商店被拒:理由「违规收集个人信息」。整改:① 裁剪权限(去掉用不到的定位)→ ② 隐私政策弹窗 + 说明用途 → ③ 第三方 SDK 过一遍合规审计 → ④ 提交复审核通过。合规不是加分项,是「入场券」——第八本讲过的个保法,在移动端是生死线。

适配术语

  • 运行时权限:用到才申请 + 优雅降级——Android 6.0+ 的规矩。
  • 版本碎片化:多系统版本 + 厂商定制——AndroidX 兼容库来扛。
  • dp / sp:密度无关单位——屏幕适配的地基。
  • 隐私合规:个保法 + 商店审核——权限最小化 + 告知同意。
  • 数据安全:HTTPS + 加密存储 + WebView 白名单。
  • targetSdk:目标版本——商店强制跟随。
  • 合规生死线:违规收集个人信息 = 下架。

本站收获:规矩 = 权限动态申请 + AndroidX 扛碎片化 + dp 管适配 + 个保法守合规。Android 开发一半是技术,一半是「守规矩」——守住了,才能上架、才能活。

附录

知识点速查 + 面试高频题

面试/上架前最后一页

Android 知识全景表

领域核心知识点一句话人话
系统架构Linux 内核、ART、沙箱进程、版本碎片化App 跑在什么上面
Kotlin空安全、扩展函数、data class、协程现代语言四爽点
四大组件Activity/Service/广播/ContentProvider + 生命周期App 的骨架
UIJetpack Compose、声明式、状态驱动、Material界面即函数
数据层Retrofit、Room、DataStore、Repository网络 + 本地存储
架构MVVM、ViewModel、Hilt、WorkManager职责分离最佳实践
协程suspend、Dispatchers、Scope、Flow异步不卡 UI
工程化Gradle、签名、多渠道、R8、上架从源码到上架
测试质量JUnit、Compose Test、ANR、启动优化、Crashlytics让 App 稳
安全适配运行时权限、AndroidX、dp、隐私合规江湖规矩

面试高频题速记

  • Activity 生命周期?→ onCreate→onStart→onResume→onPause→onStop→onDestroy(背熟)。
  • 为什么旋转屏幕数据会丢?→ Activity 重建——ViewModel 存活 / onSaveInstanceState 保存。
  • Kotlin 比 Java 好在哪?→ 空安全、协程、扩展函数、data class、简洁。
  • Compose 和 View 区别?→ 声明式 + 状态驱动 vs 命令式 XML。
  • 协程 vs 线程?→ 协程轻量挂起不占线程——几十万并发没问题。
  • 什么是 ANR?→ 主线程 5 秒无响应——重活走协程 IO。
  • MVVM 各层职责?→ UI 显示 + ViewModel 状态 + Repository 数据。
  • 为什么用 Hilt?→ 依赖注入——自动组装、易测试(Spring IoC 的 Android 版)。
  • App 上架要注意什么?→ 签名、隐私合规、targetSdk、渠道包。
  • 如何防内存泄漏?→ LeakCanary 检测 + Activity 引用清理 + 协程作用域取消。
系统 架构认知
语言 Kotlin
组件 四大件
UI Compose
数据 网络存储
架构 MVVM
异步 协程
工程 构建上架
质量 测试监控 🚀
Android 开发 = 懂系统 + 会组件 + 写 UI + 守规矩——
一半是技术,一半是「守规矩」。
进程会被杀,所以学会保存状态;
系统在碎片化,所以学会适配;
权限要动态申请,所以学会优雅;
合规是生死线,所以学会克制——
移动开发教的不是「写代码」,是「在规矩里写代码」。
🤖 🧱 💬 🖥️ 🌐 🏗️ 🔀 📦 🧪 🛡️ 🚀 🌳
✌ 语言