web-dev-qa-db-fra.com

InflateException: impossible de résoudre l'élément de menu du gestionnaire onClick

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

  1. il est facile de se tromper dans la valeur de l'attribut XML onClick, ce qui entraînera une erreur d'exécution
  2. un développeur peut refactoriser le nom de la méthode du gestionnaire de clics, sans se rendre compte qu'elle est appelée depuis une présentation (voir la raison 1)
  3. il n’est pas toujours évident de savoir quelle méthode est appelée. Surtout si la mise en page est utilisée par un fragment
  4. séparer les préoccupations de mise en page par rapport au comportement est bon. Utiliser onClick 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
35
Frank Harper

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.

72
Milagaia

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é.

16
junique

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.

9
findusl

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+.

1
Matt Zukowski

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é.

0
user1418015
@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);
}
0
user1418015

Votre méthode doit accepter un MenuItem comme seul paramètre par ici .

    public void onMenuItemClickMethod(MenuItem menuItem){
        // Do stuff here
    }
0
Mitch