[英]Android onClickListener implementation best practices
There are four ways to add an onClickListener to a clickable View (button, for example): 有四种方法可以将onClickListener添加到可单击的视图(例如按钮):
So my question is, how do you choose one of these implementation techniques over another? 所以我的问题是,你如何选择其中一种实现技术呢? Is there a best practices according to certain conditions, or is it just a matter of programmer preference? 根据某些条件是否有最佳实践,还是仅仅是程序员偏好的问题?
Here we use so called callback pattern. 这里我们使用所谓的回调模式。
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");
}
});
In our case onClick handler implements the interface View.OnClickListener. 在我们的例子中,onClick处理程序实现了View.OnClickListener接口。
Key points: 关键点:
1) Attribute in the XML file can be used only for activity, as @Karakuri mentioned it uses reflection which is slow. 1)XML文件中的属性只能用于活动,因为@Karakuri提到它使用慢的反射。
2) Anonymous inner class has special rules for access to the members of enclosing class (check [1] , [2] ). 2)匿名内部类具有访问封闭类成员的特殊规则(check [1] , [2] )。 There are some situations when memory leaks can happen (ex. threading with AsyncTask, Handlers). 在某些情况下可能发生内存泄漏(例如使用AsyncTask,Handlers进行线程处理)。
3) Here you have a full access to the members of enclosing class. 3)在这里,您可以完全访问封闭类的成员。
4) Is a variation of 3d. 4)是3d的变化。
Readability depends on your handler size, small logic can be ok to inline, but for larger blocks of code consider 3d and 4th. 可读性取决于您的处理程序大小,小逻辑可以内联,但对于较大的代码块,请考虑3d和4th。
I never use the onClick
attribute as it ties the layout to a specific Activity (it must find the method via reflection). 我从不使用onClick
属性,因为它将布局绑定到特定的Activity(它必须通过反射找到方法)。 It doesn't work on Fragments. 它不适用于碎片。
Options 2 and 3 are virtually identical. 选项2和3几乎相同。 Option 3 might be more advantageous if you want to use the private member as the OnClickListener
of multiple views. 如果要将私有成员用作多个视图的OnClickListener
,则选项3可能更有利。
Option 4 is close to option 3. One key difference is that it changes the class declaration, so if it's important to you to keep the class declaration free of interface implementations (or perhaps you need to maintain binary compatibility of some kind), you may not want to use this option. 选项4接近选项3.一个关键的区别是它改变了类声明,所以如果保持类声明不受接口实现(或者你需要保持某种二进制兼容性)的重要性,你可以不想使用这个选项。
My advice is to avoid option 1 and choose whichever fits your code style best. 我的建议是避免选项1,并选择最适合您的代码风格。 You also aren't required to use the same approach in every single place in your code. 您也不需要在代码中的每个位置使用相同的方法。
There is a four ways to use OnClickListener
. 有四种方法可以使用OnClickListener
。
To define OnClickListener
within the method call site. 在方法调用站点中定义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
}
});
}
}
First reasons why to avoid this is because it clutters up onCreate
method. 避免这种情况的第一个原因是因为它使onCreate
方法变得混乱。 This becomes even more apparent when you want to observe click events from multiple views. 当您想要观察来自多个视图的点击事件时,这一点变得更加明显。
The next reason to avoid this is because it doesn't promote code reuse if several buttons should do the same. 避免这种情况的下一个原因是,如果几个按钮应该相同,它不会促进代码重用。
The second way is almost the same as first except implementation to field is assigned in the class. 第二种方式与第一种方法几乎相同,只是在类中分配了实现到字段。
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);
}
}
This way is pretty the same as first one, only advantage is that the method could be reused for several buttons. 这种方式与第一种方式非常相似,唯一的好处是该方法可以重复用于多个按钮。
This way is to declare an inner class to implement OnClickListener
. 这种方式是声明一个内部类来实现OnClickListener
。 If it will be used multiple times is better to define the instance as a field. 如果将多次使用,最好将实例定义为字段。
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
}
}
}
The advantage of this way is that it helps to organize the code. 这种方式的优点是它有助于组织代码。 You can easily collapse this internal class and forget about it until you need to look at it. 你可以轻松地折叠这个内部类,忘记它,直到你需要查看它。
The other good reason is that it could be turned in public class and reused in other app areas. 另一个很好的理由是它可以在公共课程中转向并在其他应用领域中重复使用。
The fourth way involves Activity to implement OnClickListener
. 第四种方法涉及Activity来实现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
}
}
The first disadvantage that this way creates a public method in the Activity and there you should pass this
activity when setOnClickListener
is called. 这种方式的第一个缺点是在Activity中创建一个公共方法,并且在调用setOnClickListener
时应该传递this
活动。
Second reason to avoid this way is that if another button is added you should determine which button was clicked. 避免这种方式的第二个原因是,如果添加了另一个按钮,您应该确定单击了哪个按钮。 Then you should use switch()
or if()
statements. 然后你应该使用switch()
或if()
语句。 It isn't performed because it wastes a cycle or several for each button click. 它不会执行,因为它会为每个按钮点击浪费一个或几个周期。
Last disadvantage for this way is that difficult to organize a class. 这种方式的最后一个缺点是难以组织一个班级。 In example you have an Activity which implements multiple interfaces. 在示例中,您有一个实现多个接口的Activity。 Suddenly all of the methods from these interfaces are intertwined together, this becomes more evident after you've added methods to some of those interfaces. 突然,这些接口中的所有方法都交织在一起,在您为某些接口添加方法后,这一点变得更加明显。 Also now you can't add an interface with method named onClick
. 此外,您现在无法使用名为onClick
方法添加接口。
There is some differences between these ways, but you should choose your way according your code and needs 这些方式之间存在一些差异,但您应根据自己的代码和需求选择自己的方式
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.