6年前にこの質問をしました。それまでの間、Android開発のベストプラクティスが変更され、より良い開発者になりました。
それ以来、onClick
XML属性を使用することは悪い習慣であることを認識し、取り組んでいるコードベースから削除しました。
これで、すべてのクリックハンドラーが、XMLレイアウトではなく、アプリのコードで定義されました。
onClick
を使用しない理由は
onClick
XML属性の値を間違えると、実行時エラーになります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
私に役立つ解決策を見つけました。通常、レイアウトのonClick
属性には次のメソッドがあります
public void methodname(View view) {
// actions
}
メニュー項目(この場合はSherlockメニュー)では、次の署名に従う必要があります。
public boolean methodname(MenuItem item) {
// actions
}
したがって、あなたの問題はあなたのメソッドがvoid
ではなくboolean
を返すことでした。
私の場合、アプリケーションの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
を削除し、すべてが機能しました。
これは少し時代遅れですが、ここに例外の理由があります。クラス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メソッドを見つけようとします。したがって、onCreateOptionsMenu
でgetMenuInflater()
を呼び出す代わりに、new MenuInflater(this)
を呼び出す必要があります。これにより、this
がコンテキストとして渡され、コードが機能します。
次のようなifステートメントを使用するだけで、他のAPIバージョンにgetMenuInflater()
を引き続き使用できます。
_if (Build.VERSION.SDK_INT > 15)
inflater = getMenuInflater();
else
inflater = new MenuInflater(this);
_
15未満のAPIバージョンでもバグが発生するかどうかは実際にはわからないので、通常は保存バージョンを使用しました。
私の場合の問題は、メニューXMLに両方onClick
があり、アクティビティにonCreateOptionsMenu
があったことです。私のonClick
は実際には欠陥があります(存在しないメソッドを指し示していたため)が、Android 2.xでテストしているため、最初はこれに気付きませんでしたが、onClick
はサポートされておらず、無視されますが、4.xでテストした後、このエラーが発生し始めました。
したがって、Android 2.xの下で展開する予定の場合は、基本的にonClick
を使用しないでください。実行を試みるまで、onClick
の値は暗黙的に無視されます。 3.0+。
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);
}
メソッドは here ごとの唯一のパラメーターとしてMenuItemを受け入れる必要があります。
public void onMenuItemClickMethod(MenuItem menuItem){
// Do stuff here
}