工欲善其事,必先利其器
俗话说,“工欲善其事,必先利其器”,对致力于让计算机解决人类问题的程序员来说,更应该如此(打字慢还找什么借口……)
最开始以为程序员对使用技巧都比较关注,不过从自己和身边同事的交流来看,很多我常用的技巧尤其是快捷键,确实不少人都不太了解,于是就有了这篇文章。
本文基于Android Studio Mac版。
Android Studio基于IntelliJ IDEA Community Edition(社区版),主要是在其基础上增加了Android插件。因此Android Studio中很多功能和IDEA是相同的。
IDEA Android插件源码
https://github.com/JetBrains/android
设置
左上角菜单 Android Studio - Preferences,打开设置对话框。可以直接搜索设置项。
设置的导入/导出
File - Import Settings / Export Settings
应用场景举例:团队共享Lint检查配置、代码格式化风格
Help - Search
在菜单Help - Search中,输入任意一个不了解的功能名称,例如Reformat Code,可以看到这个功能在哪打开,并打开这个功能。所以在后面的文章里,每个功能我都会给出对应的英文名,不知道怎么打开的,直接这么搜索就能找到了。
KeyMap
对于快捷键用的少,还没有养成很强使用习惯的人,可以考虑使用Eclipse MacOS风格。
本文在括号中注明的是我自己用的快捷键,大部分基于Eclipse MacOS风格,做过一些修改。
编辑
列举几个编辑器通用的功能
-
块操作:按住Alt,上下拖动鼠标选中,可以编辑内容相似的多行。
-
缩进:选中多行,按Tab和Shift+Tab,可以批量缩进。
-
大部分软件中,缩放通常通过这几种方法实现:
- Ctrl+鼠标滚轮;
- 触控板双指捏合;
Cmd
加+/-
缩放- 在Android Studio低版本中可用触控板双指捏合,2.3版本缩放功能关了
- 绝大多数浏览器可以用
Cmd
加+/-
缩放字体大小
自动补全
图中这样的情况:
- 如果直接按回车键,被选项会插入到光标处,还需要手动删掉光标后面的内容;
- 如果按Tab键,则备选项会直接替换当前的layout属性。
Scope
Scope是IDEA中的一个通用概念,表示代码范围,可以是工程最终产出的代码(Production Files),也可以包括测试代码,可以包含Library,可以指定为某些文件、目录、包,也可以自己定义。
在Find等功能中都可以使用Scope。
很有用但往往不为人知的一个Scope是Project And Libraries,除了工程文件,还包括已经同步成功的AAR中的代码。
查找与跳转
-
Main Menu - Edit - Find,所有搜索相关功能(包括当前设置的快捷键)
-
Main Menu - View,所有查看相关功能
-
Main Menu - Navigate,所有导航相关功能
导航/跳转
-
Go To Definition 选中变量、方法、类等,跳转到定义(经典的
F3
) -
Navagate Back/Forward。往前、往后跳转。(
Cmd+[
/Cmd+]
) -
点击父类/子类class和方法声明行左侧的上下箭头,可以跳转到父类/子类中的实现。
-
Bookmarks
-
在代码任意行,选择Navigate - Bookmarks - Toggle Bookmark或定义的快捷键,可以添加、删除书签
-
选择Navigate - Bookmarks - Show Bookmarks或定义的快捷键,可以看到所有书签
-
应用场景:适合在多个文件的某几个地方反复切换的情况。
-
查看
-
Recent Files 查看最近使用的文件(
Cmd+E
) -
Quick Documentation 选中变量、方法、类等,查看JavaDoc注释(
F2
)
- 按一下快捷键,悬浮窗查看注释
- 继续按快捷键,可以在悬浮窗、独立小窗口、大窗口之间循环切换
- Type Hierarchy 选中类的声明,查看class继承关系(
F4
)
搜索
- Find Usage 查看被调用情况(
Cmd+Shift+G
)
- 默认搜索范围(Scope)是Project Files。可点击Find窗口的设置按钮,搜索范围指定为Project Files and Libraries(没有AAR包时没有这个选项),则会包含AAR包中的调用。可参考后文中对Scope的说明。
-
Search Everywhere 查找文件、设置等(
Shift Shift
) -
当前文件中Find、Replace字符串(
Cmd+F
、修改为Cmd+R
) -
所有文件中Find、Replace字符串(
Cmd+H
) -
指定文件夹中Find、Replace字符串:右击,搜索
Project Window
点击Project视图上的设置按钮(齿轮图标),菜单中可以勾选:
-
Flatten Packages:所有的包都在同一级扁平显示,而不是树形折叠/展开形式,例如
com.demo.main
com.demo.main.ui
-
Compact Empty Middle Packages:当一个package里只有一个子package,会扁平化显示在一行,而不是折叠展开的子目录形式,例如
com.demo.main
-
com
-
demo
-
main
-
com.demo.main
-
Show Members:在Project窗口,class文件还能继续展开,查看具体的成员变量、方法。
-
Autoscroll to Source:选择导航窗口中的文件、方法,会自动定位到源码对应位置。对于大工程容易卡顿,可以关掉。
-
Autoscroll from Source:查看源码,会自动定位到导航窗口中的文件、方法。对于大工程容易卡顿,可以关掉。
当Autoscroll from Source
关闭时,点击Project视图上的定位按钮(圆圈图标),可以从当前查看的源码定位到导航栏中的文件。
Code Style
Java变量前缀(prefix)的设置
-
Code Style - Java - Code Generation - Naming - Name Prefix
-
Field设置为m,Static Field设置为s
-
设置完成后,自动补全时会自动处理变量前缀
Reformat Code
-
Main Menu - Code:代码格式化、补全、查看相关
-
代码格式化(Ctrl+Shift+F)
-
格式化完成时会展示一个小气泡,点击
Show reformat dialog
,可勾选:- Optimize imports,自动优化imports
- Rearrange Code,按照一定规则,自动调整成员变量、方法、内部类的先后顺序
-
Preferences - Editor - General - Auto Import - Optimize imports on the fly:编辑代码时自动优化import
Inspections、Analyze
Inspections是IDEA中用于代码静态检查的组件,包括语法检查、拼写检查等,IDEA的Android插件实现了Lint检查,也是基于Inspections的。
-
Preference - Editor - Inspections:代码检查
-
配置分为Default和Project Default,作用范围分别是全局和当前工程
-
Lint检查到代码问题会提示警告或错误
-
Main Menu - Analyze - Inspect Code:在弹窗中选择Scope(范围),Inspection Profile(要检查的规则),可以对整个项目或指定Scope进行检查
-
Main Menu - Analyze - Code Cleanup:在弹窗中选择Scope(范围),Inspection Profile(要检查的规则),可以对整个项目或指定Scope进行格式化、Lint问题自动修复、无用变量代码等自动优化
-
Main Menu - Analyze - Analyze Dependencies:可以分析指定Scope中代码所有的依赖项。
Code Generation
-
Prefrence - Editor - General - Postfix Completion:一些常用快捷输入,例如
fori
可直接输入循环for (int i = 0; i < foo; i++) {}
-
Prefrence - Editor - Live Templates:快捷输入,例如
psvm
输入public static void main(String[] args){}
,也可以自己定义 -
Main Menu - Code - Generate
-
继承方法:直接输入父类方法名前缀,自动补全默认的继承方法
-
输入set、get,自动创建setter、getter
Intentions(Quick Fixes):没有做不到的,只有想不到的
Intentions意为“意图”,是IDEA中用于代码高级补全、自动修复的机制。在菜单Preference - Editor - Intentions中,可以查看和开关各种Intentions。
在任意代码位置,打开Show Intention Actions 自动补全(Cmd+1
),即可选择Intentions Actions操作。
-
各种代码补全
- Parcelable补全实现
- 创建构造函数
- 变量赋值移动到声明
- …
-
语法级别问题的自动优化/修复
- 添加强制转换
- 添加变量声明
- 添加try-catch或方法增加throw…
- 创建调用super的构造函数
- 逻辑表达式化简、无用逻辑删除(例如
if(true){ ... }
)
-
Android Lint问题自动修复(由IDEA中的Android插件实现)
- 解决Lint问题(例如Layout中的字符串提取到Strings中)
- 添加SupressLint
- 可以关闭当前工程中的这类问题的检查,如图
举例:快速创建字符串资源
- Layout文件中,text属性直接用了文本,没有引用String资源,会有Lint警告
- 光标点选文本,按Intentions的快捷键,选择Extract string resource
- 弹出窗口输入资源的id,确认即可
举例:快速创建XML资源文件
写Layout时,需要给ImageView写一个ShapeDrawable资源文件
- 常规方法:
- 从左侧找到Drawable目录
- 右击,创建Drawable资源文件
- 切换回Layout,引用创建的资源文件
- Intentions实现:直接在src属性中填上drawable文件的名字,会标红提示没有这个资源文件,按Intentions快捷键,选择
Create Drawable Resource File
,弹窗点击确认即可。
Refactor
Rename(Shift+F6)
-
按Shift+F6重命名:变量、类名、文件名、文件夹、包名、资源文件等
-
重命名变量,会弹窗提示是否同步重命名getter、setter
-
默认注释中的名字也会被同步改变;资源文件中的引用也会改变
-
连续按两次Shift+F6可以打开重命名窗口,勾选/取消勾选findInComment,避免修改到错误的地方
要注意的坑
-
对于名字比较短的情况,特别是资源文件、id等,很容易和注释中的东西重名,重构过程中应该先看下引用,防止误修改到错误的内容。一般会自动打开Refactoring Preview窗口预览要改的所有位置,右击选择Exclude/Include可以包含、取消要改的地方。
-
资源文件中的
.9.png
图片,重命名时容易丢失.9
扩展名,需要特别注意
Move (Cmd+Alt+V)
- 移动package(多个module中相同的包会被同步移动)
- 移动文件夹(不会处理其他module)
- 移动文件、Class
- 移动静态方法、常量
举例:XXConstants的抽取
通过Move,可以快速把代码中散落在各个文件中的SharedPreference常量,统一移动到名为SPConstants的interface中。
Change Signature (Cmd+Alt+S)
- 改变方法签名
- 方法名可改变
- 参数可以调整顺序、改变名字、类型等
- 新增的参数,可以设置默认值,会尽可能自动匹配并填充
Extract与Inline
这里快捷键做过较多改动,目前我的设置是Inline统一用快捷键Cmd+Alt+I,Extract快捷键见括号。
-
Extract/Inline Constants (Cmd+Alt+C)
-
Extract/Inline Field (Cmd+Alt+F)
-
Extract/Inline Local Variable (Cmd+Alt+L)
-
Extract/Inline Method (Cmd+Alt+M)
-
勾选static可抽取成static方法
-
可修改Parameter,同Change Signature
-
Extract/Inline Class (右键菜单-Refactor)
-
Extract/Inline Layout (右键菜单-Refactor)
-
Extract/Inline Style (右键菜单-Refactor)
注意:
-
Extract Method如果选中的代码块中产生了超过一个后面会用到的变量,就不能直接Extract,默认会提示可以建一个Object实现
-
Inline Method,如果Method中有分支return,就不能直接Inline,需要手动处理。
举例:快速抽取工具类
-
想抽取一个LogUtil方法,用于输出Log。
void func() {
Log.d("tag", System.currentTimeMillis() + "");
}
-
选中
System.currentTimeMillis() + ""
,Extrac Variable。 -
void func() {
-
String msg = System.currentTimeMillis() + "";
-
Log.d("tag", msg);
-
}
-
选中代码块
Log.d("tag", msg);
,Extrac Method。 -
输入方法名,同时勾选static。
-
Refactor-Move,移动到工具类。如果输入的工具类没建,还会提示并自动创建。
-
public class LogUtils {
-
public static void log(String msg) {
-
Log.d("tag", msg);
-
}
-
}
-
void func() {
-
String msg = System.currentTimeMillis() + "";
-
LogUtils.log(msg);
-
}
举例:内联接口和父类
写了一个抽象类class Cls implements MyInterface
,实现了接口,现在想把接口去掉,抽象方法直接定义在抽象类中
- 光标选中MyInterface
- Inline
- 选择As is
- 注:继承类的情况也可以这么用,不过可能会有一些同名变量等冲突,需要手动再处理下。
举例:匿名内部类移到成员变量中
-
要将直接实例化的匿名类移到成员变量中,原代码如下。
void f() {
setRunnable(new Runnable() {
@Override
public void run() {
// ...
}
});
}
-
选中
new Runnable(){}
代码块,Refactor,Extract Field。-
private Runnable mRunnable;
-
void f() {
-
mRunnable = new Runnable() {
-
@Override
-
public void run() {
-
// ...
-
}
-
};
-
setRunnable(mRunnable);
-
}
-
-
Extract默认不会改变代码逻辑,Runnable的实例化和赋值还是在方法中,可以选择Intentions,
Move assignment to field declaration
,将赋值移到Field声明的地方。-
private Runnable mRunnable = new Runnable() {
-
@Override
-
public void run() {
-
// ...
-
}
-
};
-
void f() {
-
setRunnable(mRunnable);
-
}
-
举例:批量替换Deprecated方法
-
历史代码中,实现了一个Log工具类,且代码中有大量的调用。
-
之后发现老的工具类定义不合理,打Log时不能指定Tag,于是新实现了一个Log工具类,并将原有的方法标记为Deprecated。
-
void f1() {
-
deprecated_log("my_msg_1");
-
}
-
void f2() {
-
deprecated_log("my_msg_2");
-
}
-
// ...
-
@Deprecated
-
void deprecated_log(String msg) {
-
Log.d("old_tag", msg);
-
}
-
void log(String tag, String msg) {
-
Log.d(tag, msg);
-
}
-
-
现在想把老的工具类调用全部替换成新的工具类。手工替换非常繁琐而且容易出错,但是使用Inline可以很快解决问题。
-
步骤一:修改deprecated方法,让其调用新的工具类。
@Deprecated
void deprecated_log(String msg) {
log("old_tag", msg);
}
-
步骤二:选中deprecated方法调用的位置,Inline,选择
Inline all invocations and remove the method
,确认,则所有Deprecated方法都会被内联成新的工具方法。
Refactor Members
- Push Members Up
- Pull Members Down
举例:写了一个Class,现在想将其中一些方法抽取成接口
- class implements MyInterface
- 自动补全,创建MyInterface
- Pull Members Up
- 选中新建的接口,勾选要抽取的方法
- Done
TODO
代码注释中增加TODO
,在IDEA中默认会显示成蓝色;在TODO窗口中可以看到所有的TODO,且可以设置Scope过滤。
应用场景举例
-
在重构老代码时特别有用,因为有很多小的点,可能在新的代码结构中一时不好实现,可以加个TODO后期再完成。
-
需求开发过程中有一些需要等待确认的点,可以先写一个TODO。
-
开发过程中用代码实现了一些假数据,开发完了要删掉,可以写一个TODO避免后面忘记删。
Debug
Attach
对于设备上已经运行的Debug版App,点击Attach debugger to Android process
,选择进程即可调试,不需要重新编译安装。如果改动的代码和被调试代码无关且不影响行号,也不需要重新编译安装。
变量
修改变量值
在Variables窗口会显示当前所有变量,右击变量 - Set Value,可以直接修改值。
查看变量和表达式的值
在Watches窗口点加号,可以添加和查看变量、表达式的值。点击Show watches in variables tab
按钮,可以切换Watches显示成独立窗口,还是和Variables显示在一起。
断点
查看断点
点击View Breakpoints可以查看所有断点,快速启用、禁用、删除断点。
禁用断点
点击Mute Breakpoints,可以临时快速禁用所有断点。
变量断点、方法断点
单击成员变量、方法定义行的左侧,可打变量断点、方法断点。只要有对变量、方法的访问,就会断点。
条件断点
单击代码左侧可以打断点,右击红色断点标志,在弹窗的Condition中输入返回boolean的表达式,即可作为条件断点,当表达式成立时就会断点
Gradle
Gradle Sync
Android Studio中,会通过Gradle Sync的过程,下载更新所有依赖项,将JAR/AAR源码或class关联到工程,输出到build/generated
目录,建立起代码之间的关联,从而实现代码跳转、补全等功能。
从Gradle Console的输出可以看到,实际执行的是prepareComXxx
,generateXxx
等Gradle Task。
除了修改Gradle脚本、编译,Sync操作也可以直接点击工具栏或Gradle Projects窗口中的按钮触发。
Run Configurations
点击运行的三角形时,默认会执行编译(gradle assemble)、安装(gradle install)等操作,可以在Edit Configurations窗口中,指定同时要执行的其他Gradle任务,如图。
Version Control
Version Control包括git、CVS等版本控制工具(以插件形式安装),以及Android Studio自带的版本控制(代码修改的撤销等)。
-
Preferences - Version Control:可设置IDE保存的可以回退的历史记录条数,还有常用的git项目关联。
-
关联git后,右击代码窗口左侧 - Annotate,可以查看最近的git修改记录。
-
更多git功能可以在Main Menu - VCS - git中找到。