J'ai posé cette question il y a 6 ans. Entre-temps, les meilleures pratiques de développement Android ont changé et je suis devenu un meilleur développeur.
Depuis lors, j'ai compris que l'attribut XML onClick
était une mauvaise pratique et je l'ai supprimé de toute base de code sur laquelle je travaille.
Tous mes gestionnaires de clics sont maintenant définis dans le code de l'application, pas dans les dispositions XML!
Mes raisons de ne jamais utiliser onClick
sont
onClick
, ce qui entraînera une erreur d'exécutiononClick
les mélange, ce qui est mauvais! J'espère vous avoir convaincu de ne jamais utiliser onClick
dans une mise en page :)!
Ci-dessous se trouve ma question initiale, qui illustre assez bien pourquoi utiliser onClick
est une mauvaise idée.
===
Je définis des éléments de menu au format XML et tente d'utiliser l'attribut onClick ajouté à l'API 11. Lorsque l'activité est lancée dans un émulateur exécutant la version 4.0.3, les exceptions suivantes se produisent:
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)
Je ne comprends pas la cause de l'exception, car la méthode suivante est définie dans mon activité.
import com.actionbarsherlock.view.MenuItem;
...
public void onFeedbackMenu( MenuItem menuItem ) {
Toast.makeText( this, "onFeedBack", Toast.LENGTH_LONG ).show();
}
Mon fichier de définition de menu XML contient:
<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>
Pour assurer la compatibilité ascendante, j'utilise ActionBarSherlock, mais je reçois également une exception très similaire lorsque je lance l'application sur la version 2.3.x.
Ceci est une version plus complète de la trace de pile
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
J'ai trouvé une solution qui fonctionnait pour moi . Généralement, l'attribut onClick
dans une présentation a la méthode suivante
public void methodname(View view) {
// actions
}
Sur un élément de menu (dans ce cas, le menu Sherlock), il doit suivre la signature suivante:
public boolean methodname(MenuItem item) {
// actions
}
Donc, votre problème était que votre méthode renvoyait void
et non boolean
.
Dans mon cas, le AndroidManifest.xml
de mon application (démarré par l'assistant Eclipse par défaut) contenait Android:theme="@style/AppTheme"
dans le bloc <application>
.
Lors du débogage de la cause du problème, il s’est avéré que la ligne
mMethod = c.getMethod(methodName, PARAM_TYPES);
dans Android.view.MenuInflater/InflatedOnMenuItemClickListener
a été appelé avec c
n'étant pas ma classe Activity
mais un Android.view.ContextThemeWrapper
douteux (qui, bien sûr, ne contient pas le gestionnaire onClick).
Donc, j'ai enlevé le Android:theme
et tout a fonctionné.
Bien que ce soit un peu obsolète, voici la raison de l’exception. Lorsque vous examinez les sources de l'API Android 15 (4.0.3-4.0.4) dans la classe MenuInflater, vous verrez cette méthode:
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;
}
C’est là où l’exception se produit, comme Junique l’a déjà souligné. Cependant, la suppression du thème de l'application n'est qu'une solution de contournement et aucune option réelle. Comme nous le voyons, la méthode essaie de trouver la méthode Callback sur la classe de l'élément de contexte transmis. Ainsi, au lieu d'appeler getMenuInflater()
dans onCreateOptionsMenu
, vous devriez appeler new MenuInflater(this)
, pour que this
soit passé en tant que contexte et que le code fonctionne.
Vous pouvez toujours utiliser getMenuInflater()
pour d'autres versions de l'API si vous utilisez simplement une instruction if comme ceci:
if (Build.VERSION.SDK_INT > 15)
inflater = getMenuInflater();
else
inflater = new MenuInflater(this);
Je ne sais pas vraiment si le bogue survient aussi dans les versions d'api de moins de 15 ans, alors j'ai généralement utilisé la version de sauvegarde.
Dans mon cas, le problème était que j'avais les deux onClick
dans mon menu XML et un onCreateOptionsMenu
dans mon activité. Ma onClick
était en fait défectueuse (car elle indiquait des méthodes inexistantes), mais je ne l'avais pas remarquée au début, car je testais sous Android 2.x, où onClick
n'est ni pris en charge ni ignoré. Une fois que j'ai testé sur 4.x cependant, j'ai commencé à obtenir cette erreur.
Donc, en gros, n'utilisez pas onClick
si vous envisagez de déployer sous Android 2.x. Il ignorera en silence vos valeurs onClick
jusqu'à ce que vous essayiez de fonctionner sous 3.0+.
J'ai constaté que j'avais le même problème avec les éléments de menu ActionBar et leurs événements onClick. Ce que j’ai découvert, c’est que le poste de travail dans lequel je travaille était à court de mémoire et devait être redémarré. Android VM est maintenant capable de résoudre le nom de méthode référencé.
@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);
}
Votre méthode doit accepter un MenuItem comme seul paramètre par ici .
public void onMenuItemClickMethod(MenuItem menuItem){
// Do stuff here
}