快捷键:把鼠标操作换成键盘

IDE 的效率差距,八成来自快捷键的熟练度。下面这些动作每天会做几十次,值得专门练到肌肉记忆。

  • 快速搜索一切:Shift 连按两次,搜类名、文件、动作、设置项,一个入口解决大部分“我要找什么”。
  • 查找定义与用法:Ctrl + 点击跳转定义,Ctrl + Alt + B 查实现,Alt + F7 查所有引用。
  • 文件与符号内搜索:Ctrl + F 当前文件,Ctrl + Shift + F 全工程,Ctrl + F12 看方法结构。
  • 编辑增强:Ctrl + D 复制行,Ctrl + Y 删除行,Alt + Shift + 上下移动整行,Ctrl + Alt + L 格式化。
  • 重构:Shift + F6 重命名,Ctrl + Alt + M 提取方法,Ctrl + Alt + V 提取变量。

建议只先练五个最常用的,一周内就能形成习惯。贪多记不住,反而会退回鼠标操作。

实时模板与代码生成

实时模板(Live Templates)用几个字母展开成一段代码,是省时间最直接的方式。Android Studio 内置了不少,也可以自定义。

常用内置模板
  • logt生成带当前类名 TAG 的日志语句,配合过滤标签快速定位。
  • toast生成 Toast 调用,写临时提示非常快。
  • ifn / inn生成 if (x == null) 与 if (x != null) 判空分支。
  • fori / foreach生成索引循环与增强循环,避免手敲括号。
Android Studio 示意:正对视角的抽象代码编辑器窗口,四周环绕闪电、齿轮、放大镜与键盘等发光效率工具图标
效率工具环绕编辑器:快捷键、模板、分析器共同构成日常开发的工作台。

除了输入模板,还要善用“生成”菜单(Alt + Insert):快速生成构造函数、getter/setter、equals/hashCode、重写方法与测试类。这些样板代码手写既慢又容易出错。

重构:安全改名与移动

“全局替换”是最危险的操作之一,它会把注释、字符串和其他无关位置一起改掉。重构功能才是安全的选择,因为它基于语义分析。

  • 重命名(Shift + F6):同时更新所有引用(含其他模块与 XML 资源引用),并可预览改动范围。
  • 移动(F6):把类从一个包移到另一个包,自动修正 import。
  • 提取方法 / 变量 / 参数(Ctrl + Alt + M / V / P):把长函数拆开,是改善可读性最常用的一招。
  • 内联(Ctrl + Alt + N):把多余的中间变量与包装函数去掉。
  • 改变签名(Ctrl + F6):增删参数、调整顺序,一次性更新所有调用点。

良好的习惯是:每次重构后立刻跑一次单元测试或编译。小步快跑,出问题时改动范围小、回退成本低。

调试器:断点、条件断点与变量求值

调试器远比 print 日志强大,尤其是条件断点与变量求值这两个功能,能省下大量重复运行的时间。

  • 条件断点:右键断点设置条件(如 userId == "1024"),只在满足条件时暂停,避免在一万次循环里点一万次继续。
  • 日志断点:不暂停,只打印表达式,相当于不用改代码的动态日志。
  • 求值表达式:暂停时可直接对任意表达式求值,验证你的假设而不用重新编译。
  • 异常断点:在抛出指定异常时自动暂停,用于定位偶发崩溃的源头。
  • 变量观察:把关键对象加入 Watches,单步执行时随时查看其状态变化。

附件进程调试时,记得在 build.gradle 里开启 debuggable,否则断点不会生效。这一步经常被忽略,导致反复怀疑 IDE。

调试完的逻辑值得固化成单元测试:在 IDE 里点方法名旁的绿色箭头就能直接跑,之后每次改动都会自动回归。下面这个测试针对“手机号脱敏”与“协程状态流”,覆盖了断言、异常与异步等待三个常用场景:

import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test

class PhoneFormatTest {

    // 同步逻辑:普通断言即可
    @Test
    fun `11 位手机号应脱敏为 3+4 星号`() {
        assertEquals("138****8000", maskPhone("13800138000"))
    }

    @Test
    fun `非法长度原样返回`() {
        assertEquals("123", maskPhone("123"))
        assertTrue(maskPhone("").isEmpty())
    }

    // 异步逻辑:用 runTest 等待状态流,避免虚拟时间导致测试变慢
    @Test
    fun `加载成功后状态应变为 Loaded`() = runTest {
        val vm = UserViewModel(repo = FakeRepo())
        vm.load("u_1")
        val state = vm.state.first { it !is Loading }   // 等到第一个非 Loading 状态
        assertTrue(state is Loaded)
        assertEquals("绿码", (state as Loaded).user.name)
    }
}

注意最后一段使用了 runTest 与 first { } 的组合:前者让挂起函数在测试线程里同步推进,后者避免读取到中间态。这样写出的测试既稳定又快,不会因为真实网络或延迟而随机失败。

分析器:CPU、内存与网络

Android Studio 内置的 Profiler 覆盖了性能排查的三大方向,用熟之后定位问题会快很多。

方向能回答的问题典型用法
CPU谁在占用主线程?录制一段操作,看调用火焰图里最宽的块
内存对象为什么越来越多?抓堆快照,按类名排序找泄漏增长点
网络请求为什么慢?看单个请求的时间线与响应体大小
能耗后台为什么耗电?关联定位、网络与唤醒锁的使用情况

使用建议:录制时间控制在 10 到 20 秒,且只做一件明确的事(如“冷启动到首页可见”)。录制太长、操作太多,火焰图会变成一团糊,什么都看不出来。

版本控制与 Git 集成

IDE 内置的 Git 集成能做到“几乎不切命令行”,但前提是理解几个关键视图。

  • Annotate(右键行号区域):逐行显示最后修改者与提交信息,排查“这行谁改的、为什么改”非常高效。
  • Local Changes / Commit 面板:分块暂存(chunk),把不相关的改动分开提交。
  • 冲突解决:三方合并视图,确认左右差异后再接受,不要盲目点“全部接受”。
  • Shelve / Stash:临时切换分支时保存当前改动。
# 命令行里同样常用的三组操作
git log --oneline -20                      # 最近 20 条提交
git diff --stat HEAD~1                     # 上次提交改了哪些文件
git stash push -m "临时保存:改样式"         # 带说明的暂存,避免日后忘记内容

提交习惯上坚持两点:一次提交只做一件事;提交信息写清“为什么改”而不是“改了什么”——后者从 diff 就能看出来。