Android 充气异常:无法';t解析菜单项onClick处理程序

Android 充气异常:无法';t解析菜单项onClick处理程序,android,android-actionbar,actionbarsherlock,Android,Android Actionbar,Actionbarsherlock,我6年前问过这个问题。与此同时,Android开发最佳实践已经改变,我已经成为一名更好的开发人员 从那时起,我意识到使用onClickXML属性是一种不好的做法,并将其从我处理的任何代码库中删除 我所有的点击处理程序现在都是在应用程序的代码中定义的,而不是在XML布局中定义的 我从不使用onClick的原因如下 onClickXML属性的值很容易出错,这将导致运行时错误 开发人员可能会重构click handler方法的名称,而没有意识到它是从布局中调用的(参见原因1) 找出实际调用的方法并不总

我6年前问过这个问题。与此同时,Android开发最佳实践已经改变,我已经成为一名更好的开发人员

从那时起,我意识到使用
onClick
XML属性是一种不好的做法,并将其从我处理的任何代码库中删除

我所有的点击处理程序现在都是在应用程序的代码中定义的,而不是在XML布局中定义的

我从不使用onClick的原因如下

  • onClick
    XML属性的值很容易出错,这将导致运行时错误
  • 开发人员可能会重构click handler方法的名称,而没有意识到它是从布局中调用的(参见原因1)
  • 找出实际调用的方法并不总是显而易见的。尤其是当布局被片段使用时
  • 将布局和行为的关注点分开是好的。使用
    onClick
    将它们混合在一起,这很糟糕 我希望我已经说服您不要在布局中使用
    onClick
    :)

    下面是我的原始问题,它很好地说明了为什么使用
    onClick
    是个坏主意

    ===

    我正在用XML定义菜单项,并尝试使用API 11中添加的onClick属性。在运行4.0.3的模拟器中启动活动时,会出现以下异常:

    FATAL EXCEPTION: main
    android.view.InflateException: Couldn't resolve menu item onClick handler 
        onFeedbackMenu in class android.view.ContextThemeWrapper
    
    ...
    Caused by: java.lang.NoSuchMethodException: onFeedbackMenu 
        [interface com.actionbarsherlock.view.MenuItem]
    at java.lang.Class.getConstructorOrMethod(Class.java:460)
    
    我不明白是什么导致了异常,因为我的活动中定义了以下方法

    import com.actionbarsherlock.view.MenuItem;
    ...
    public void onFeedbackMenu( MenuItem menuItem ) { 
        Toast.makeText( this, "onFeedBack", Toast.LENGTH_LONG ).show();
    }
    
    我的XML菜单定义文件包含:

    <menu xmlns:android="http://schemas.android.com/apk/res/android" >
    ...
        <item
            android:id="@+id/menu_feedback"
            android:icon="@drawable/ic_action_share"
            android:showAsAction="ifRoom"
            android:title="@string/menu_feedback"
            android:onClick="onFeedbackMenu" />
    </menu>
    
    
    ...
    
    为了向后兼容,我使用ActionBarSherlock,当我在2.3.x上运行应用程序时,也会遇到一个非常类似的异常

    这是堆栈跟踪的更完整版本

    FATAL EXCEPTION: main
    android.view.InflateException: Couldn't resolve menu item onClick handler 
        onFeedbackMenu in class android.view.ContextThemeWrapper
        at com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener.<init>(MenuInflater.java:204)
        at com.actionbarsherlock.view.MenuInflater$MenuState.setItem(MenuInflater.java:410)
        at com.actionbarsherlock.view.MenuInflater$MenuState.addItem(MenuInflater.java:445)
        at com.actionbarsherlock.view.MenuInflater.parseMenu(MenuInflater.java:175)
        at com.actionbarsherlock.view.MenuInflater.inflate(MenuInflater.java:97)
        ...
    Caused by: java.lang.NoSuchMethodException: onFeedbackMenu 
        [interface com.actionbarsherlock.view.MenuItem]
        at java.lang.Class.getConstructorOrMethod(Class.java:460)
        at java.lang.Class.getMethod(Class.java:915)
        at com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener.<init>(MenuInflater.java:202)
        ... 23 more
    
    致命异常:main
    android.view.InflateException:无法解析单击处理程序时的菜单项
    android.view.ContextThemeWrapper类中的OnFeedback菜单
    在com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener上。(MenuInflater.java:204)
    在com.actionbarsherlock.view.MenuInflater$MenuState.setItem(MenuInflater.java:410)上
    在com.actionbarsherlock.view.MenuInflater$MenuState.addItem(MenuInflater.java:445)上
    在com.actionbarsherlock.view.MenuInflater.parseMenu(MenuInflater.java:175)上
    在com.actionbarsherlock.view.MenuInflater.inflate上(MenuInflater.java:97)
    ...
    原因:java.lang.NoSuchMethodException:onFeedbackMenu
    [接口com.actionbarsherlock.view.MenuItem]
    位于java.lang.Class.GetConstructorMethod(Class.java:460)
    位于java.lang.Class.getMethod(Class.java:915)
    在com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener上。(MenuInflater.java:202)
    ... 23多
    
    我发现ActionBar菜单项及其onClick事件也存在同样的问题。我发现我正在开发的工作站内存不足,需要重新启动。Android VM现在能够解析引用的方法名。

    我找到了一个适合我的解决方案。
    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
    {
        getMenuInflater().inflate(R.menu.activity_main, menu);
    
        MenuItem item = menu.findItem(R.id.menu_open);
    
        if (item == null)
            return true;
    
        item.setOnMenuItemClickListener
        (
            new MenuItem.OnMenuItemClickListener () 
            { 
                public boolean onMenuItemClick(MenuItem item) 
                { return (showDirectory(item)); }
            } 
        ); 
    
        return true;
    }
    
    
    public boolean showDirectory (MenuItem item)
    {
        CheckBox checkBox = (CheckBox) findViewById (R.id.checkBox1);
        checkBox.setChecked(true);
    }
    
    通常布局中的
    onClick
    属性具有以下方法

    public void methodname(View view) { 
        // actions
    }
    
    在菜单项(本例中为Sherlock菜单)上,应遵循以下签名:

    public boolean methodname(MenuItem item) { 
        // actions
    }
    

    因此,您的问题是您的方法返回了
    void
    而不是
    boolean
    ,在我的例子中,问题是我的菜单XML中既有
    onClick
    ,也有
    oncreateoptions菜单中的
    。我的
    onClick
    实际上是错误的(因为它指向的是不存在的方法),但一开始我没有注意到这一点,因为我在Android 2.x下进行测试,其中
    onClick
    不受支持且被忽略。但是,当我在4.x上测试时,我开始出现这个错误


    因此,如果您计划在Android 2.x下部署,基本上不要使用
    onClick
    。在你尝试在3.0+上运行之前,它会自动忽略你的
    onClick
    值。

    在我的例子中,我的应用程序(由默认Eclipse助手启动)的
    android:theme=“@style/AppTheme”
    块中包含
    android:theme=“@style/AppTheme”

    在调试问题的原因时,结果发现

    mMethod = c.getMethod(methodName, PARAM_TYPES);
    
    android.view.MenuInflater/InflatedOnMenuItemClickListener
    中,调用
    c
    不是我的
    Activity
    类,而是一个可疑的
    android.view.ContextThemeWrapper
    (当然不包含onClick处理程序)


    因此,我删除了android:theme,一切都正常了。

    虽然这有点过时,但下面是例外的原因。当您在MenuInflater类中查看android API 15(4.0.3-4.0.4)的源代码时,您将看到以下方法:

    public InflatedOnMenuItemClickListener(Context context, String methodName) {
    mContext = context;
    Class<?> c = context.getClass();
    try {
        mMethod = c.getMethod(methodName, PARAM_TYPES);
    } catch (Exception e) {
        InflateException ex = new InflateException(
                "Couldn't resolve menu item onClick handler " + methodName +
                " in class " + c.getName());
        ex.initCause(e);
        throw ex;
    }
    

    实际上,我不知道该错误是否也发生在15以下的api版本中,所以我通常使用保存版本。

    您的方法必须接受MenuItem作为其唯一的参数


    更新,当我重新启动时,我没有意识到出现的Android虚拟机是2.3.3。但是,当我特别选择Android VM为4.0.3时,我继续得到onClick的错误。@覆盖公共布尔onCreateOptions菜单(菜单菜单菜单){getMenuInflater().inflate(R.Menu.activity_main,Menu);MenuItem item=Menu.findItem(R.id.Menu\u open);if(item==null)返回true;item.setOnMenuItemClickListener(新建MenuItem.OnMenuItemClickListener(){public boolean onMenuItemClick(MenuItem项){return(showDirectory(item));}}});返回true;}基于此线程。。建议程序员使用menu.findItem()和finditembyd()更新菜单。为此,在OnCreateOptions菜单或OnPrepareOptions菜单中维护菜单选项。。这里讨论。。我认为另一件事是幸福的
    if (Build.VERSION.SDK_INT > 15)
            inflater = getMenuInflater();
        else
            inflater = new MenuInflater(this);
    
        public void onMenuItemClickMethod(MenuItem menuItem){
            // Do stuff here
        }