在Android Studio中开发,解决方案不会总是一蹴而成的。作为一个有效率的编程者,在你的开发,调试和测试中需要一些弹性以及代码重构。随着在这章中的行进,你将明白Android Studio如何产生代码;在这章里你将看到Android Studio如何重构你的代码。重构代码最大的风险是可能引入不期望的错误。通过分析某些风险重构操作的结果,Android Studio减低了这些风险,然后激活Find tool窗口,在发行前,你可以预览你的更改-那里标志着任何错误或冲突。
无论怎样,你必须避免强行重构(例如:通过一个全文的查找/替换操作来重组代码),因为在这些情形下Android Studio不能从引入的错误中一直保护你。相反,如果Android Studio发现你企图一个重构操作,它将尽力避免你犯任何愚蠢错误。例如,在Project tool窗口中拖动一个JAVA源文件从一个包到另一个包,这将强制产Refactor ➤ Move操作,由此会分析你的移动操作结果,允许你预览那些改变,然后适当地改变类中所有的import语句以适应合格的新全包名。
绝大多数的重构操作被限制于一个方法或一个类里面,因而将不太会引入错误到你的项目中。危险的重构操作是那些涉及到两个或以上的资源文件。如果重构操作引入编译错误,检查管理器将在编辑器里用红标签标志那些被影响的资源文件。基于这点,你或者可以企图去修正它们,或者用Ctrl+Z|Cmd+Z简单地取消这个重构操作了。如果重构操作以没有编译错误完成,然而涉及到太多资源文件,那你还是必须要测试及校验你是否引入了任何实时错误。第11章涵盖了测试。
提示:你必须提交任何重要的重构更改,作为单一的Git提交,因此之后你可以轻松地回复那个提交。 这章聚焦于用最好的工具来执行重构操作。在我们探访独立的重构操作之前,我们乐于指出Android Studio有一个极其便利的重构工具叫Refactor ➤Refactor This.总在上下文菜单中选择这个,图4-1所示,集成了绝大多数有用的重构操作。快捷键是Ctrl+Alt+Shift+T | Ctrl+T,在PC上你可以方便地记首字母CAST。

- 重命名 在Project tool窗口中选择Sandbox并导航到Refactor➤ Rename或按Shift+F6.引出一个对话框以允许你重命名你的类,另外也可以重命名出现在注释中,测试实例,以及继承类中的那些名字。重命名Sandbox为Playpen并点击Refactor按钮,如图4-2所示。你将看到在你项目中重命名的操作。现在请用Ctrl+Z | Cmd+Z取消这个操作。

- 修改签名
更改签名的操作允许你改变方法的下列属性:可视性,名称,返回类型,参数,以及例外抛出。在Sandbox.java里创建一个方法,如下面的代码片断:
public String greetings(String message){ return "Hello " + message; } 将光标移到单词greetings上面(高亮的粗体字)并按Ctrl+F6 |Cmd+F6,或导航到Refactor ➤ Change Signature。结果对话框会允许你修改方法的签名,如图4-3所示。

在参数表里,点击字符串类型参数message这项,将它的名称从message改为greet。
- 类型移植
如标题所述,类型移植允许你从一个JAVA类型移植到另一个。让我们假设你创建了一个Person类。随着你的开发进行,你发现Person太一般了,因而你又创建了一个Manager类扩展于Person。如果你想移植所有的Person实例到Manager,你可以用类型移植轻松办到。
将光标放到greetings方法的String声明上(在下面代码片段中的高亮粗体字)并且按Ctrl+Shift+F6 | Cmd+Shift+F6或选择Refactor ➤ Type Migration。结果对话框如图4-4所示。
public String greetings(String greet){ return "Hello " + greet; }
4.析出
析出不是一个操作而是几个。这节涵括了一些重要的析出操作:析出变量,析出常量,析出域,析出参数,和析出方法。在·Sandbox.class·里,让我们先移走所有的成员变量和方法从白纸开始:
public class Sandbox {
}
5.析出变量
在你的Sandbox.java类里,定义一个方法如下示:
private String saySomething(){ return "Something"; } 把光标放到硬编码Something的值(粗体字)上并选择Refactor ➤ Extract ➤ Variable,或者按Ctrl+Alt+V | Cmd+Alt+V接着按回车,不要选择声明final的复选框。Android Studio依据硬编码字符串析出一个本地变量并命名它。你将以如下代码告终:
private String saySomething(){ String something = "Something"; return something; }
- 析出常量
当你开发Android的APP时,会发现你会用很多的字符串作为键-例如,在Map和Bundle里。因此,析出常量将会节省你大量的时间。
定义一个方法象如下的代码片段。把光标放到name_key字符串上并按Ctrl+Alt+C | Cmd+Alt+C。结果对话框将如图4-9所示。这里,Android Studio提供一些建议的名称。按惯例,常量在JAVA里都应该是大写的。选择NAME_KEY并按回车。 注意:为了创建和处理这个方法而不发生编译错误,你必须导入android.os.Bundle
private void addName(String name, Bundle bundle ){ bundle.putString("name_key", name); } 结束时你将看一个常量名称是NAME_KEY,象以下定义的:
public static final String NAME_KEY = "name_key";
7.析出域
析出域将转换一个本地变量到你的类域(a.k.a.成员变量)里。 注意:为了创建和处理这个方法而不发生编译错误,你必须导入android.os.Bundle 在你的Sandbox类里定义一个方法:
private Date getDate(){ return new Date(); } 把光标放到Date(粗体高亮)上并按键Ctrl+Alt+F | Cmd+Alt+F。你将看到一个对话框如图4-10所示。在Android里,按惯例域(a.k.a. 成员变量)名的头字母用m。你将会注意到一个下拉菜单允许你初始化当前方法中的域,域声明,或构造器。选择域声明并按回车。
8.析出参数
析出参数允许你析出一个变量并放到封套的方法里。在你的Sandbox类里定义一个方法:
private void setDate(){
mDate = new Date();
}
将光标放到Date()(粗体高亮)上,按Ctrl+Alt+P | Cmd+Alt+P接着按回车。结果这个方法如下代码片段所示:
private void setDate(Date date){
mDate = date;
}
- 析出方法
析出方法让你选择一行或多行行连续的代码放到一个分离的方法中。有两个原因你会想做这个。首先是方法太复杂了。相对于100行的代码,打断它到约10到20行的算法块会比较容易阅读且会较少错误。
再者,重复的代码从来就不是好主意,因而如果你发现了重复的代码,最好析出它们成一个方法并在重复的地方调用它。通过析出之前重复的代码到一个方法里并调用它,你可以保留你的方法在一个地方,如果你想修改它,你只要修改一次。
private String methodHello (){
String greet = "Hello";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
private String methodGoodbye (){
String greet = "Goodbye";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
第二 高级重构
整个这章所描述的剩下的其他重构操作是高级别的。如果你有兴趣简单迅速地提高Android Studio,已经有了足够的知识来有效地使用重构操作,也许你可以跳过这节。但无论如何,如果你对JAVA有比较好的理解并且想钻研更多的重构操作,继续看下去吧。
移除Sandbox.java里的所有成员变量及方法,从一张白纸开始。
public class Sandbox {
} 右键点击(Mac电脑用Ctrl+点击)Project tool窗口里的com.apress.gerber.helloworld包,选择New ➤ Java Class。命名这个类为Minibox。修改Minibox类定义继承自Sandbox并且有个成员变量叫做mShovel,如这里所示:
public class Minibox extends Sandbox {
private String mShovel;
}
- 推高成员变量以及拉低成员变量
推高成员变量以及拉低成员变量用于继承。注意到我们定义了一个mShovel成员变量在Minibox类里。让我们假设mShovel可能对于其他继承自Sandbox类的子类也有用。这样做,打开Minibox类并选择Refactor ➤ Pull Members Up。结果对话框如图4-13所示。

mShovel会被缺省地选中,并且因为Sandbox是Minibox的父类所以推高成员变量组合窗口会缺省地设定在com.apress.gerber.helloworld.Sandbox类上。点击Refactor,检视Sandbox和Minibox,你将发现mShovel成员变量不再出现在Minibox里了,而属于Sandbox。作为一般规则,如果你觉得一个成员变量对其他扩展类也是有用的,那么就把这些成员变量在继承层次里推高。用类似的手法可以拉低成员变量。
- 解除继承并委托成员变量 右键点击(Mac电脑用Ctrl+点击)com.apress.gerber.helloword包选择New ➤ Java Class。命名这个新类为Patio并继承自Sandbox:
public class Patio extends Sandbox {
}
进一步分析后,我们决定Patio不是一个Sandbox,但更象是它拥有一个Sandbox。为了改变它们的关系,导航到Refactor ➤ Replace Inheritance with Delegation。在结果对话框里,点击为委托成产生getter方法,如图4-14所示。
- 用工厂方法代替构造器 把光标放在Sandbox类定义附栏内。按Alt+Insert | Cmd+N接着选择生成一个新构造器。选择所有成员变量,如图4-17所示,然后点击OK。

将光标放到如下所示代码片段构造器的任何位置,并导航到Refactor ➤ Replace Constructor with Factory Method。结果对话框象图4-18所示。点击Refactor来生成一个工厂方法。 public Sandbox(String shovel, int children) {
mShovel = shovel;
mChildren = children;
}

注意到之前的构造器现在变成private了并且一个新的静态方法返回Sandbox类的实例,如下面代码片段所示。如果你正创建一个单例类,这将会是非常有用的。
public static Sandbox createSandbox(String shovel, int children) {
return new Sandbox(shovel, children);
}