从我读过,您可以通过两种方式为按钮分配 onClick
处理程序 .
使用 android:onClick
XML属性,您只需使用带有签名 void name(View v)
的公共方法的名称,或使用 setOnClickListener
方法传递实现 OnClickListener
接口的对象 . 后者通常需要一个我个人不喜欢的匿名类(个人品味)或定义实现 OnClickListener
的内部类 .
通过使用XML属性,您只需要定义一个方法而不是一个类,所以我想知道是否可以通过代码而不是XML布局来完成相同的操作 .
16 回答
请注意,如果要使用onClick XML功能,则相应的方法应该有一个参数,其类型应与XML对象匹配 .
例如,一个按钮将通过其名称字符串链接到您的方法:
android:onClick="MyFancyMethod"
但方法声明应显示:...MyFancyMethod(View v) {...
如果您尝试将此功能添加到菜单项,它将在XML文件中具有完全相同的语法,但您的方法将声明为:
...MyFancyMethod(MenuItem mi) {...
是的,你可以让
fragment
或activity
实施View.OnClickListener
当您在代码中初始化新的视图对象时,您可以简单地执行
mView.setOnClickListener(this);
这会自动设置代码中的所有视图对象,以使用
fragment
或activity
等具有的onClick(View v)
方法 .要区分哪个视图调用
onClick
方法,可以在v.getId()
方法上使用switch语句 .This answer is different from the one that says "No that is not possible via code"
android:onClick
适用于API级别4以上,因此如果您_557568使用它 .要小心,虽然
android:onClick
XML似乎是处理click的一种方便的方法,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)
不,这不可能通过代码 . Android只在您定义
android:onClick="someMethod"
属性时为您实现OnClickListener
.这两个代码片段是相同的,只是以两种不同的方式实现 .
Code Implementation
以上是
OnClickListener
的代码实现 . 这是XML实现 .XML Implementation
在后台,Android只执行Java代码,在单击事件上调用您的方法 .
请注意,使用上面的XML,Android将仅在当前的Activity中查找
onClick
方法myFancyMethod()
. 如果您正在使用片段,这一点很重要,因为即使您使用片段添加上面的XML,Android也不会在用于添加XML的片段的.java
文件中查找onClick
方法 .我注意到的另一件重要事情你提到你不喜欢匿名方法 . 你的意思是说你不喜欢匿名 classes .
我在xml文件中写这段代码...
并在片段中编写此代码...
使用Java 8,您可以使用Method Reference来实现您想要的功能 .
假设这是一个按钮的
onClick
事件处理程序 .然后,在这样的
setOnClickListener()
调用中传递onMyButtonClicked
实例方法引用 .这样可以避免自己明确定义匿名类 . 但我必须强调Java 8的方法参考实际上只是一个语法糖 . 它实际上为您创建了一个匿名类的实例(就像lambda表达式一样),因此当您注册事件处理程序时,应用了lambda-expression-style事件处理程序时的类似注意事项 . 这article解释得非常好 .
PS . 对于那些对如何在Android中真正使用Java 8语言功能感到好奇的人来说,它是retrolambda库的礼貌 .
支持Ruivo的答案,是的,您必须将方法声明为“公共”才能在Android的XML onclick中使用 - 我正在开发一个针对API Level 8的应用程序(minSdk ...)到16(targetSdk ...) .
我宣称我的方法是私有的,它引起了错误,只是宣称它是公共作品 .
检查您是否忘记将该方法公之于众!
这里有很好的答案,但我想添加一行:
在XML的
android:onclick
中,Android在场景后面使用java reflection来处理这个问题 .并且as explained here,反射总是会降低性能 . (特别是在Dhalvik VM上) . 注册
onClickListener
是一种更好的方法 .指定
android:onClick
属性会导致Button
实例在内部调用setOnClickListener
. 因此绝对没有区别 .为了清楚地理解,让我们看看框架如何处理XML
onClick
属性 .当布局文件膨胀时,实例化其中指定的所有视图 . 在此特定情况下,
Button
实例是使用public Button (Context context, AttributeSet attrs, int defStyle)构造函数创建的 . XML标记中的所有属性都从资源包中读取,并作为AttributeSet
传递给构造函数 .Button
类继承自View
类,这导致调用View
构造函数,它负责通过setOnClickListener
设置单击回调处理程序 .attrs.xml中定义的onClick属性在View.java中称为
R.styleable.View_onClick
.以下是View.java的代码,它通过单独调用
setOnClickListener
来完成大部分工作 .如您所见,调用
setOnClickListener
来注册回调,就像我们在代码中一样 . 唯一的区别是它使用Java Reflection
来调用我们的Activity中定义的回调方法 .以下是其他答案中提到的问题的原因:
Callback method should be public :由于使用了Java Class getMethod,因此仅搜索具有公共访问说明符的函数 . 否则准备好处理
IllegalAccessException
异常 .While using Button with onClick in Fragment, the callback should be defined in Activity :
getContext().getClass().getMethod()
调用将方法搜索限制为当前上下文,在Fragment的情况下为Activity . 因此,在Activity类中搜索方法而不是Fragment类 .Callback method should accept View parameter :由于Java Class getMethod搜索接受
View.class
作为参数的方法 .设置单击侦听器的另一种方法是使用XML . 只需将android:onClick属性添加到您的标记即可 .
尽可能在匿名Java类上使用xml属性“onClick”是一种很好的做法 .
首先,让我们来看看代码的区别:
XML Attribute / onClick attribute
XML部分
Java部分
Anonymous Java Class / setOnClickListener
XML部分
Java部分
以下是在匿名Java类上使用XML属性的好处:
使用Anonymous Java类时,我们总是必须为元素指定一个id,但是可以省略XML属性id .
使用匿名Java类,我们必须主动搜索视图内部的元素(findViewById部分),但是使用Android属性,Android会为我们做 .
正如我们所看到的,匿名Java类至少需要5行代码,但使用XML属性时,3行代码就足够了 .
使用Anonymous Java类,我们必须命名我们的方法“onClick”,但是使用XML属性我们可以添加我们想要的任何名称,这将极大地帮助我们的代码的可读性 .
Google在API级别4发布期间添加了
Xml“onClick”属性,这意味着它的语法更加现代,现代语法几乎总是更好 .
当然,并不总是可以使用Xml属性,这就是为什么我们不选择它的原因:
如果我们正在使用片段 . onClick属性只能添加到一个活动中,所以如果我们有一个片段,我们就必须使用一个匿名类 .
如果我们想将onClick侦听器移动到一个单独的类(可能是因为它非常复杂和/或我们想在应用程序的不同部分重用它),那么我们就不想使用xml了属性要么 .
假设,你想添加像这样的点击事件
main.xml
在java文件中,您必须编写类似此方法的方法 .
执行此操作的最佳方法是使用以下代码:
当我看到最顶层的答案时,它让我意识到我的问题不是将参数(View v)放在花哨的方法上:
当试图从xml访问它时,应该使用
希望能帮助别人 .