据我所知,您可以通过两种方式为按钮分配onClick
处理程序。
使用android:onClick
XML属性,您只需使用带有签名void name(View v)
的公共方法的名称,或使用setOnClickListener
方法传递实现{{{1}的对象1}}接口。后者通常需要一个我不喜欢的匿名类(个人品味)或定义实现OnClickListener
的内部类。
通过使用XML属性,您只需要定义一个方法而不是一个类 想知道是否可以通过代码而不是XML布局来完成相同的工作。
答案 0 :(得分:565)
不,这是不可能通过代码。 Android只会在您定义OnClickListener
属性时为您实现android:onClick="someMethod"
。
这两个代码片段是相同的,只是以两种不同的方式实现。
代码实施
Button btn = (Button) findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myFancyMethod(v);
}
});
// some more code
public void myFancyMethod(View v) {
// does something very interesting
}
以上是OnClickListener
的代码实现。这是XML实现。
XML实施
<?xml version="1.0" encoding="utf-8"?>
<!-- layout elements -->
<Button android:id="@+id/mybutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me!"
android:onClick="myFancyMethod" />
<!-- even more layout elements -->
在后台,Android只做Java代码,在点击事件上调用你的方法。
请注意,使用上述XML,Android只会在当前的Activity中查找onClick
方法myFancyMethod()
。如果您正在使用片段,这一点很重要,因为即使您使用片段添加上面的XML,Android也不会在用于添加片段的片段的onClick
文件中查找.java
方法。 XML。
我注意到的另一件重要事情。您提到您不喜欢匿名方法。你的意思是说你不喜欢匿名类。
答案 1 :(得分:82)
当我看到最佳答案时,它让我意识到我的问题不是将参数(View v)放在花哨的方法上:
public void myFancyMethod(View v) {}
尝试从xml访问它时,应该使用
android:onClick="myFancyMethod"/>
希望能有所帮助。
答案 2 :(得分:72)
android:onClick
适用于API级别4以上,因此,如果您的目标是&lt; 1.6,那你就不能用了。
答案 3 :(得分:30)
检查您是否忘记将该方法公开!
答案 4 :(得分:26)
在内部指定android:onClick
属性导致Button
实例调用setOnClickListener
。因此绝对没有区别。
为了清楚地理解,让我们看看框架如何处理XML onClick
属性。
当布局文件膨胀时,其中指定的所有视图都会被实例化。在此特定情况下,使用public Button (Context context, AttributeSet attrs, int defStyle)
构造函数创建Button
实例。 XML标记中的所有属性都从资源包中读取,并作为AttributeSet
传递给构造函数。
Button
类继承自View
类,导致调用View
构造函数,负责通过setOnClickListener
设置点击回调处理程序。
attrs.xml中定义的onClick属性在View.java中称为R.styleable.View_onClick
。
以下是View.java
的代码,它通过单独调用setOnClickListener
为您完成大部分工作。
case R.styleable.View_onClick:
if (context.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot "
+ "be used within a restricted context");
}
final String handlerName = a.getString(attr);
if (handlerName != null) {
setOnClickListener(new OnClickListener() {
private Method mHandler;
public void onClick(View v) {
if (mHandler == null) {
try {
mHandler = getContext().getClass().getMethod(handlerName,
View.class);
} catch (NoSuchMethodException e) {
int id = getId();
String idText = id == NO_ID ? "" : " with id '"
+ getContext().getResources().getResourceEntryName(
id) + "'";
throw new IllegalStateException("Could not find a method " +
handlerName + "(View) in the activity "
+ getContext().getClass() + " for onClick handler"
+ " on view " + View.this.getClass() + idText, e);
}
}
try {
mHandler.invoke(getContext(), View.this);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not execute non "
+ "public method of the activity", e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("Could not execute "
+ "method of the activity", e);
}
}
});
}
break;
如您所见,调用setOnClickListener
来注册回调,就像我们在代码中一样。唯一的区别是它使用Java Reflection
来调用我们的Activity中定义的回调方法。
以下是其他答案中提到的问题的原因:
Java Class getMethod
,因此只搜索具有公共访问说明符的函数。否则准备处理IllegalAccessException
例外。getContext().getClass().getMethod()
调用将方法搜索限制为当前上下文,如果是片段,则为Activity。因此,在Activity类中搜索方法而不是Fragment类。Java Class getMethod
搜索接受View.class
作为参数的方法。答案 5 :(得分:13)
请注意,如果要使用onClick XML功能,则相应的方法应该有一个参数,其类型应与XML对象匹配。
例如,按钮将通过其名称字符串android:onClick="MyFancyMethod"
链接到您的方法,但方法声明应显示:
...MyFancyMethod(View v) {...
如果您尝试将此功能添加到菜单项,它将在XML文件中具有完全相同的语法,但您的方法将声明为:...MyFancyMethod(MenuItem mi) {...
答案 6 :(得分:11)
这里有很好的答案,但我想添加一行:
在XML的android:onclick
中,Android在场景后面使用java reflection来处理此问题。
as explained here,反射总是会降低性能。 (特别是在Dhalvik VM上)。注册onClickListener
是一种更好的方式。
答案 7 :(得分:5)
设置on click侦听器的另一种方法是使用XML。只需将android:onClick属性添加到您的标记中即可。
最好尽可能在匿名Java类上使用xml属性“onClick”。
首先,让我们看一下代码的区别:
XML属性/ onClick属性
XML部分
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:onClick="showToast"/>
Java部分
public void showToast(View v) {
//Add some logic
}
匿名Java类/ setOnClickListener
XML部分
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Java部分
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//Add some logic
}
});
以下是在匿名Java类上使用XML属性的好处:
当然,并不总是可以使用Xml属性,以下是我们不选择它的原因:
答案 8 :(得分:4)
通过使用XML属性,您只需要定义一个方法而不是 一个类,所以我想知道是否可以通过代码完成相同而不是 XML布局。
是的,您可以fragment
或activity
实施View.OnClickListener
当您在代码中初始化新的视图对象时,您只需执行mView.setOnClickListener(this);
并自动设置代码中的所有视图对象,以使用onClick(View v)
或fragment
等具有的activity
方法。
要区分哪个视图调用了onClick
方法,您可以在v.getId()
方法上使用switch语句。
这个答案不同于说#34;不能通过代码&#34;
答案 9 :(得分:4)
Add Button in xml and give onclick attribute name that is the name of Method.
<!--xml --!>
<Button
android:id="@+id/btn_register"
android:layout_margin="1dp"
android:onClick="addNumber"
android:text="Add"
/>
Button btnAdd = (Button) findViewById(R.id.mybutton); btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addNumber(v);
}
});
Private void addNumber(View v){
//Logic implement
switch (v.getId()) {
case R.id.btnAdd :
break;
default:
break;
}}
答案 10 :(得分:4)
使用Java 8,您可以使用Method Reference来实现您想要的目标。
假设这是一个按钮的onClick
事件处理程序。
private void onMyButtonClicked(View v) {
if (v.getId() == R.id.myButton) {
// Do something when myButton was clicked
}
}
然后,您在onMyButtonClicked
这样的调用中传递setOnClickListener()
实例方法引用。
Button myButton = (Button) findViewById(R.id.myButton);
myButton.setOnClickListener(this::onMyButtonClicked);
这将允许您自己避免显式定义匿名类。但我必须强调Java 8的方法参考实际上只是一个语法糖。它实际上为您创建了一个匿名类的实例(就像lambda表达式一样),因此当您取消注册事件处理程序时,应用了类似于lambda-expression-style事件处理程序的注意事项。这个article解释得非常好。
PS。对于那些对如何在Android中真正使用Java 8语言功能感到好奇的人来说,这是retrolambda库的礼貌。
答案 11 :(得分:3)
支持Ruivo的回答,是的,您必须将方法声明为“公共”才能在Android的XML onclick中使用 - 我正在开发一个从API Level 8(minSdk ...)到16(targetSdk ... )。
我将我的方法声明为私有,并且导致错误,只是将其声明为公共作品。
答案 12 :(得分:1)
假设您要添加点击事件,例如main.xml
<Button
android:id="@+id/btn_register"
android:layout_margin="1dp"
android:layout_marginLeft="3dp"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:onClick="register"
android:text="Register"
android:textColor="#000000"/>
在java文件中,您必须编写类似此方法的方法。
public void register(View view) {
}
答案 13 :(得分:1)
答案 14 :(得分:1)
请注意,虽然android:onClick
XML似乎是处理点击的便捷方式,但setOnClickListener
实施除了添加onClickListener
之外还有其他功能。实际上,它将视图属性clickable
设置为true。
虽然在大多数Android实现中它可能不是问题,但根据电话构造函数,按钮始终默认为clickable = true但某些手机型号上的其他构造函数可能在非Button视图上具有默认的clickable = false。
因此设置XML是不够的,你必须一直认为在非按钮上添加android:clickable="true"
,如果你有一个设备,其中默认值是clickable = true,你甚至忘记了一次XML属性,您不会在运行时发现问题,但会在客户手中获得市场反馈!
此外,我们永远无法确定proguard将如何对XML属性和类方法进行模糊处理和重命名,因此不能100%安全地确保它们有一天不会出现错误。
因此,如果您从未想过遇到麻烦而从未考虑过,那么最好使用setOnClickListener
或像ButterKnife这样的库注释@OnClick(R.id.button)
答案 15 :(得分:0)
执行此操作的最佳方法是使用以下代码:
Button button = (Button)findViewById(R.id.btn_register);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do your fancy method
}
});
答案 16 :(得分:0)
我在xml文件中写这段代码......
<Button
android:id="@+id/btn_register"
android:layout_margin="1dp"
android:layout_marginLeft="3dp"
android:layout_marginTop="10dp"
android:layout_weight="2"
android:onClick="register"
android:text="Register"
android:textColor="#000000"/>
将此代码写入片段......
public void register(View view) {
}
答案 17 :(得分:0)
要使您的生活更轻松并避免setOnClicklistener()中的Anonymous Class,请实现如下所示的View.OnClicklistener接口:
公共类YourClass扩展CommonActivity实现View.OnClickListener,...
这可以避免:
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
yourMethod(v);
}
});
并直接转到:
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.your_view:
yourMethod();
break;
}
}