web-dev-qa-db-ja.com

InflateException:メニュー項目のonClickハンドラーを解決できませんでした

6年前にこの質問をしました。それまでの間、Android開発のベストプラクティスが変更され、より良い開発者になりました。

それ以来、onClick XML属性を使用することは悪い習慣であることを認識し、取り組んでいるコードベースから削除しました。

これで、すべてのクリックハンドラーが、XMLレイアウトではなく、アプリのコードで定義されました。

onClickを使用しない理由は

  1. onClick XML属性の値を間違えると、実行時エラーになります
  2. 開発者は、レイアウトから呼び出されることに気付かずに、クリックハンドラーメソッドの名前をリファクタリングする可能性があります(理由1を参照)
  3. 実際に呼び出されているメソッドを見つけることは、必ずしも明白ではありません。特にレイアウトがフラグメントによって使用されている場合
  4. レイアウトと動作の懸念を分離することは良いことです。 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
35
Frank Harper

私に役立つ解決策を見つけました。通常、レイアウトのonClick属性には次のメソッドがあります

public void methodname(View view) { 
    // actions
}

メニュー項目(この場合はSherlockメニュー)では、次の署名に従う必要があります。

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

したがって、あなたの問題はあなたのメソッドがvoidではなくbooleanを返すことでした。

74
Milagaia

私の場合、アプリケーションのAndroidManifest.xml(デフォルトのEclipseアシスタントによってキックスタート)のAndroid:theme="@style/AppTheme"<application>ブロックに含まれていました。

問題の原因をデバッグすると、行が

mMethod = c.getMethod(methodName, PARAM_TYPES);

in Android.view.MenuInflater/InflatedOnMenuItemClickListenerが呼び出されましたが、cは私のActivityクラスではなく、怪しげなAndroid.view.ContextThemeWrapperです(もちろん、onClickハンドラーは含まれていません)。

それで、Android:themeを削除し、すべてが機能しました。

16
junique

これは少し時代遅れですが、ここに例外の理由があります。クラス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;
}
_

ジュニークがすでに指摘したように、これは例外の発生でした。ただし、アプリのテーマの削除は回避策にすぎず、実際のオプションはありません。ご覧のとおり、メソッドは渡されたコンテキスト項目のクラスでCallbackメソッドを見つけようとします。したがって、onCreateOptionsMenugetMenuInflater()を呼び出す代わりに、new MenuInflater(this)を呼び出す必要があります。これにより、thisがコンテキストとして渡され、コードが機能します。

次のようなifステートメントを使用するだけで、他のAPIバージョンにgetMenuInflater()を引き続き使用できます。

_if (Build.VERSION.SDK_INT > 15)
        inflater = getMenuInflater();
    else
        inflater = new MenuInflater(this);
_

15未満のAPIバージョンでもバグが発生するかどうかは実際にはわからないので、通常は保存バージョンを使用しました。

9
findusl

私の場合の問題は、メニューXMLに両方onClickがあり、アクティビティにonCreateOptionsMenuがあったことです。私のonClickは実際には欠陥があります(存在しないメソッドを指し示していたため)が、Android 2.xでテストしているため、最初はこれに気付きませんでしたが、onClickはサポートされておらず、無視されますが、4.xでテストした後、このエラーが発生し始めました。

したがって、Android 2.xの下で展開する予定の場合は、基本的にonClickを使用しないでください。実行を試みるまで、onClickの値は暗黙的に無視されます。 3.0+。

1
Matt Zukowski

ActionBarメニュー項目とそのonClickイベントに同じ問題があることがわかりました。私が発見したのは、開発中のワークステーションのメモリが不足していて、再起動する必要があったことです。 Android VMは、参照されるメソッド名を解決できるようになりました。

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

メソッドは here ごとの唯一のパラメーターとしてMenuItemを受け入れる必要があります。

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