inflateexception: не удалось разрешить пункт меню в обработчике клика

<p>я задал этот вопрос 6 лет назад. за это время передовые практики разработки под android изменились, и я стал лучшим разработчиком.</p><p>с тех пор я понял, что использование xml-атрибута <code>onclick</code> - плохая практика, и удалил его из любой базы кода, над которой я работаю.</p><p>все мои обработчики кликов теперь определены в коде приложения, а не в макетах xml!</p><p>мои причины никогда не использовать <code>onclick</code></p><ol> <li>легко допустить ошибку в значении атрибута xml <code>onclick</code>, что приведет к ошибке во время выполнения</li> <li>разработчик может реорганизовать имя метода обработчика кликов, не осознавая, что он вызывается из макета (см. причину 1)</li> <li>выяснить, какой метод на самом деле вызывается, не всегда очевидно. особенно, если макет используется фрагментом</li> <li>разделение проблем макета против поведения - это хорошо. использование <code>onclick</code> смешивает их, что плохо! </li> </ol><p>я надеюсь, что убедил вас никогда не использовать <code>onclick</code> в макете :)!</p><p>ниже мой оригинальный вопрос, который является довольно хорошей иллюстрацией того, почему использование <code>onclick</code> является плохой идеей.</p><p>===</p><p>я определяю пункты меню в xml и пытаюсь использовать атрибут onclick, который был добавлен в api 11. когда activity запускается в эмуляторе под управлением 4.0.3, возникают следующие исключения:</p><pre><code>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) </code></pre><p>я не понимаю, что является причиной исключения, так как в моей деятельности определен следующий метод</p><pre><code>import com.actionbarsherlock.view.menuitem; ... public void onfeedbackmenu( menuitem menuitem ) { toast.maketext( this, "onfeedback", toast.length\_long ).show(); } </code></pre><p>мой файл определения меню xml содержит:</p><pre><code><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> </code></pre><p>для обратной совместимости я использую actionbarsherlock, а также получаю очень похожее исключение при запуске приложения на 2.3.x.</p><p>это более полная версия трассировки стека</p><pre><code>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.(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 </code></pre>

<p>я нашел решение, которое сработало для меня . обычно атрибут <code>onclick</code> в макете имеет следующий метод</p><pre><code>public void methodname(view view) { // actions } </code></pre><p>в пункте меню (в данном случае в меню «шерлок») должна следовать следующая подпись:</p><pre><code>public boolean methodname(menuitem item) { // actions } </code></pre><p>итак, ваша проблема заключалась в том, что ваш метод возвратил <code>void</code>, а не <code>boolean</code>.</p>

<p>в моем случае <code>androidmanifest.xml</code> моего приложения (запущенного по умолчанию помощником eclipse) содержал <code>android:theme="@style/apptheme"</code> в блоке <code><application></code>.</p><p>при отладке причины проблемы оказалось, что строка</p><pre><code>mmethod = c.getmethod(methodname, param\_types); </code></pre><p>в <code>android.view.menuinflater/inflatedonmenuitemclicklistener</code> вызывался с <code>c</code> не моим классом <code>activity</code>, а сомнительным <code>android.view.contextthemewrapper</code> (который, конечно, не содержит обработчик onclick).</p><p>итак, я удалил <code>android:theme</code> и все заработало.</p>

<p>хотя это немного устарело, вот причина для исключения. когда вы посмотрите на источники android api 15 (4.0.3-4.0.4) в классе menuinflater, вы увидите этот метод:</p><pre><code>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; } </code></pre><p>это было исключение, как уже указала юник. однако удаление темы приложения - это просто обходной путь, а не реальный вариант. как мы видим, метод пытается найти метод callback в классе передаваемого элемента контекста. поэтому вместо вызова <code>getmenuinflater()</code> в <code>oncreateoptionsmenu</code> вы должны вызвать <code>new menuinflater(this)</code>, чтобы <code>this</code> передавался как контекст, а затем код работал.</p><p>вы все еще можете использовать <code>getmenuinflater()</code> для других версий api, если вы просто используете оператор if, подобный этому:</p><pre><code>if (build.version.sdk\_int > 15) inflater = getmenuinflater(); else inflater = new menuinflater(this); </code></pre><p>на самом деле я не знаю, происходит ли ошибка в версиях api под 15, поэтому я просто использовал версию сохранения.</p>

<p>в моем случае проблема заключалась в том, что у меня был<strong> и </strong><code>onclick</code> в моем меню xml, и <code>oncreateoptionsmenu</code> в моей деятельности. мой <code>onclick</code> был фактически неисправен (потому что он указывал на несуществующие методы), но я сначала не заметил этого, потому что я тестировал под android 2.x, где <code>onclick</code> не поддерживается и игнорируется. после того, как я проверил на 4.x, я начал получать эту ошибку.</p><p>в общем, не используйте <code>onclick</code>, если вы планируете развертывать под android 2.x. он будет игнорировать ваши значения <code>onclick</code> до тех пор, пока вы не попробуете запустить 3.0+.</p>

<p>я обнаружил, что у меня была та же проблема с элементами меню actionbar и их событиями onclick. я обнаружил, что на рабочей станции, на которой я работаю, не хватило памяти, и ее необходимо перезагрузить. android vm теперь может разрешать имя метода, на которое ссылаются.</p>

<pre><code>@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); } </code></pre>

<p>ваш метод должен принять menuitem в качестве единственного параметра для <a href="https://developer.android.com/guide/topics/resources/menu-resource">здесь</a> .</p><pre><code> public void onmenuitemclickmethod(menuitem menuitem){ // do stuff here } </code></pre>