android:onClick XML属性与setOnClickListener有什么不同?

Deadly 提交于 2020-02-28 08:59:39

根据我的读物,您可以通过两种方式将onClick处理程序分配给按钮。

使用android:onClick XML属性,在其中您仅使用带有签名void name(View v)的公共方法的名称,或者使用setOnClickListener方法,在其中传递实现OnClickListener接口的对象。 后者通常需要一个我个人不喜欢的匿名类(个人喜好)或定义一个实现OnClickListener的内部类。

通过使用XML属性,您只需要定义一个方法而不是一个类,因此我想知道是否可以通过代码而不是在XML布局中完成相同的操作。


#1楼

支持Ruivo的答案,是的,您必须将方法声明为“ public”才能在Android的XML onclick中使用-我正在开发一个应用程序,其目标是API级别8(minSdk ...)到16级(targetSdk ...)。

我将我的方法声明为私有方法,并且导致错误,只是将其声明为公共方法很好。


#2楼

请注意,如果要使用onClick XML功能,则相应的方法应具有一个参数,其类型应与XML对象匹配。

例如,一个按钮将通过其名称字符串链接到您的方法: android:onClick="MyFancyMethod"但方法声明应显示: ...MyFancyMethod(View v) {...

如果您尝试将此功能添加到菜单项 ,则它在XML文件中的语法将完全相同,但是您的方法将声明为: ...MyFancyMethod(MenuItem mi) {...


#3楼

当我看到最佳答案时,这使我意识到我的问题不是将参数(视图v)放在fancy方法上:

public void myFancyMethod(View v) {}

当尝试从xml访问它时,应使用

android:onClick="myFancyMethod"/>

希望能对某人有所帮助。


#4楼

通过使用XML属性,您只需要定义一个方法而不是一个类,因此我想知道是否可以通过代码而不是在XML布局中完成相同的操作。

是的,您可以使您的fragmentactivity实现View.OnClickListener

当您在代码中初始化新的视图对象时,您只需执行mView.setOnClickListener(this);

并自动将代码中的所有视图对象设置为使用fragmentactivity等具有的onClick(View v)方法。

为了区分哪个视图调用了onClick方法,可以在v.getId()方法上使用switch语句。

这个答案与“没有,不可能通过代码”这样的答案不同。


#5楼

指定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在代码中一样,将调用setOnClickListener来注册回调。 唯一的区别是它使用Java Reflection来调用我们的Activity中定义的回调方法。

这是其他答案中提到的问题的原因:

  • 回调方法应该是public :由于使用了Java Class getMethod ,因此仅搜索具有公共访问说明符的函数。 否则准备处理IllegalAccessException异常。
  • 在Fragment中将Button与onClick结合使用时,应在Activity中定义回调getContext().getClass().getMethod()调用将方法搜索限制为当前上下文,在Fragment情况下为Activity。 因此,方法是在Activity类而不是Fragment类中搜索的。
  • 回调方法应接受View参数 :由于Java Class getMethod搜索接受View.class作为参数的方法。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!