有四种方法可以将onClickListener添加到可点击视图(例如按钮):
- 在布局文件中设置指向活动中方法的onClick属性
- 创建一个匿名内部类
- 将onClickListener分配给私有成员变量
- 让"活动"上下文实现onClickListener接口
所以我的问题是,如何选择这些实现技术中的一种而不是另一种?是否有根据特定条件的最佳实践,或者这只是程序员偏好的问题?
这里我们使用所谓的回调模式。
public class Button {
private Callback callback;
public Button(Callback callback) {
this.callback = callback;
}
public void update() {
// Check if clicked..
callback.onClick(this);
}
public interface Callback {
public void onClick(Button Button);
}
}
Button b = new Button(new Callback() {
@Override
public void onClick(Button b) {
System.out.println("Clicked");
}
});
在我们的例子中,onClick处理程序实现了View.OnClickListener.接口
要点:
- 与活性/片段的一致性
- 访问活动/片段的成员
- 可读性
- @Michael Krause展示了关于内存泄漏的另一个优点
1) XML文件中的属性只能用于活动,因为@Karakuri提到它使用的反射很慢。
2) 匿名内部类具有访问封闭类成员的特殊规则(检查[1],[2])。在某些情况下可能会发生内存泄漏(例如,使用AsyncTask的线程、Handlers)。
3) 在这里,您可以完全访问封闭类的成员。
4) 是3d的变体。
可读性取决于处理程序的大小,小逻辑可以内联,但对于较大的代码块,请考虑3d和4th。
我从不使用onClick
属性,因为它将布局与特定的"活动"联系在一起(它必须通过反射找到方法)。它对碎片不起作用。
选项2和选项3实际上完全相同。如果您想使用私有成员作为多个视图的OnClickListener
,则选项3可能更有利。
备选方案4接近备选方案3。一个关键的区别是它更改了类声明,因此,如果保持类声明不包含接口实现(或者可能需要保持某种二进制兼容性)对您来说很重要,那么您可能不想使用此选项。
我的建议是避免选项1,选择最适合您代码风格的选项。您也不需要在代码中的每个地方都使用相同的方法。
使用OnClickListener
有四种方法。
第一种方式
在方法调用站点中定义OnClickListener
。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = findViewById(R.id.myButton);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// do something
}
});
}
}
避免这种情况的第一个原因是它混淆了onCreate
方法。当您希望从多个视图观察单击事件时,这一点会变得更加明显
避免这种情况的下一个原因是,如果几个按钮应该做同样的事情,它不会促进代码重用。
第二种方式
第二种方法与第一种方法几乎相同,只是在类中分配了字段的实现。
public class MainActivity extends AppCompatActivity {
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// do something
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = findViewById(R.id.myButton);
button.setOnClickListener(clickListener);
}
}
这种方法和第一种方法非常相似,唯一的优点是该方法可以对多个按钮重复使用。
第三种方式
这种方法是声明一个内部类来实现OnClickListener
。如果它将被多次使用,最好将实例定义为字段。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = findViewById(R.id.myButton);
button.setOnClickListener(new ButtonClick());
}
class ButtonClick implements View.OnClickListener {
@Override
public void onClick(View v) {
// do something
}
}
}
这种方式的优点是有助于组织代码。你可以很容易地折叠这个内部类,然后忘记它,直到你需要查看它。
另一个很好的原因是它可以在公共类中打开,并在其他应用程序领域中重复使用。
第四种方式
第四种方法是活动来实现OnClickListener
。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = findViewById(R.id.myButton);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// do something
}
}
第一个缺点是,这种方式在"活动"中创建了一个公共方法,并且在调用setOnClickListener
时应该传递this
活动
避免这种方式的第二个原因是,如果添加了另一个按钮,您应该确定单击了哪个按钮。然后应该使用switch()
或if()
语句。它没有执行,因为每次单击按钮都会浪费一个或多个周期
这种方式的最后一个缺点是很难组织课堂。在示例中,您有一个实现多个接口的"活动"。突然间,这些接口中的所有方法都交织在一起,在向其中一些接口添加方法后,这一点变得更加明显。同样,现在您不能使用名为onClick
的方法添加接口。
这些方法之间有一些差异,但您应该根据您的代码和需求来选择您的方法