私が読んだことから、2つの方法でonClick
ハンドラをボタンに割り当てることができます。
Publicメソッドの名前をsignaturevoid name(View v)
と一緒に使用する場合、またはsetOnClickListener
メソッドを使用してOnClickListener
インターフェースを実装するオブジェクトを渡す場合は、Android:onClick
XML属性を使用します。後者はしばしば私が嫌いな(個人的な好み)またはOnClickListener
を実装する内部クラスを定義する匿名クラスを必要とします。
XML属性を使用することで、クラスの代わりにメソッドを定義するだけでよいので、XMLレイアウトではなくコードを使用して同じことができるかどうか疑問に思いました。
いいえ、それはコードでは不可能です。 Android:onClick="someMethod"
属性を定義すると、AndroidはOnClickListener
を実装するだけです。
これら2つのコードスニペットは同等で、2つの異なる方法で実装されています。
コードの実装
Button btn = (Button) findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myFancyMethod(v);
}
});
// some more code
public void myFancyMethod(View v) {
// does something very interesting
}
上記はOnClickListener
のコード実装です。そしてこれがXMLの実装です。
XMLの実装
<?xml version="1.0" encoding="utf-8"?>
<!-- layout elements -->
<Button Android:id="@+id/mybutton"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="Click me!"
Android:onClick="myFancyMethod" />
<!-- even more layout elements -->
バックグラウンドでは、AndroidはJavaコード以外に何もしません。クリックイベントでメソッドを呼び出します。
上記のXMLでは、Androidは現在のActivityでのみonClick
メソッドmyFancyMethod()
メソッドを探します。フラグメントを使用している場合、AndroidはXMLの追加に使用されたフラグメントの.Java
ファイルでonClick
メソッドを探しません。
私が気づいたもう一つの重要なこと。あなたは匿名の methods を好まないと述べました。あなたは匿名の classes が好きではないと言うつもりでした。
私が一番上の答えを見たとき、私の問題はファンシーメソッドにパラメータ(View v)を置いていないことを私は理解しました:
public void myFancyMethod(View v) {}
Xmlからそれにアクセスしようとするとき、人は使うべきです
Android:onClick="myFancyMethod"/>
誰かに役立つことを願っています。
Android:onClick
はAPIレベル4以降を対象としているため、1.6未満をターゲットにしている場合は使用できません。
メソッドを公開するのを忘れていないか確認してください。
Android:onClick
属性を指定すると、Button
インスタンスは内部的にsetOnClickListener
を呼び出します。したがって、まったく違いはありません。
明確に理解するために、XMLのonClick
属性がフレームワークによってどのように処理されるかを見てみましょう。
レイアウトファイルが膨張すると、その中で指定されているすべてのビューがインスタンス化されます。この場合、Button
インスタンスは public Button (Context context, AttributeSet attrs, int defStyle)
コンストラクタを使用して作成されます。 XMLタグ内のすべての属性はリソースバンドルから読み取られ、AttributeSet
としてコンストラクタに渡されます。
Button
クラスはView
クラスから継承され、その結果View
コンストラクタが呼び出されます。これにより、setOnClickListener
を介してクリックコールバックハンドラが設定されます。
attrs.xml で定義されているonClick属性は、View.JavaではR.styleable.View_onClick
として参照されています。
これが View.Java
のコードで、setOnClickListener
を単独で呼び出すことで、ほとんどの作業をあなたのために行います。
case R.styleable.View_onClick:
if (context.isRestricted()) {
throw new IllegalStateException("The Android:onClick attribute cannot "
+ "be used within a restricted context");
}
final String handlerName = a.getString(attr);
if (handlerName != null) {
setOnClickListener(new OnClickListener() {
private Method mHandler;
public void onClick(View v) {
if (mHandler == null) {
try {
mHandler = getContext().getClass().getMethod(handlerName,
View.class);
} catch (NoSuchMethodException e) {
int id = getId();
String idText = id == NO_ID ? "" : " with id '"
+ getContext().getResources().getResourceEntryName(
id) + "'";
throw new IllegalStateException("Could not find a method " +
handlerName + "(View) in the activity "
+ getContext().getClass() + " for onClick handler"
+ " on view " + View.this.getClass() + idText, e);
}
}
try {
mHandler.invoke(getContext(), View.this);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not execute non "
+ "public method of the activity", e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("Could not execute "
+ "method of the activity", e);
}
}
});
}
break;
ご覧のとおり、コードで行ったように、コールバックを登録するためにsetOnClickListener
が呼び出されます。唯一の違いは、アクティビティで定義されたコールバックメソッドを呼び出すためにJava Reflection
を使用することです。
これは他の答えで述べられる問題の理由です:
Java Class getMethod
が使用されるため、publicアクセス指定子を持つ関数のみが検索されます。そうでなければIllegalAccessException
例外を処理する準備ができています。getContext().getClass().getMethod()
呼び出しは、現在のコンテキスト(フラグメントの場合はActivity)にメソッド検索を制限します。したがって、methodはFragmentクラスではなくActivityクラス内で検索されます。Java Class getMethod
から はパラメータとしてView.class
を受け入れるメソッドを検索します。OnClick XML機能を使用する場合は、対応するメソッドに1つのパラメータがあり、そのタイプはXMLオブジェクトと一致する必要があります。
たとえば、 ボタン は、名前文字列:Android:onClick="MyFancyMethod"
によってメソッドにリンクされますが、メソッド宣言は次のようになります。...MyFancyMethod(View v) {...
この機能を メニュー項目 に追加しようとしている場合は、XMLファイルでもまったく同じ構文になりますが、メソッドは次のように宣言されます。...MyFancyMethod(MenuItem mi) {...
ここには非常に良い答えがありますが、1行追加したいと思います。
XMLのAndroid:onclick
では、Androidはこれを処理するために Javaリフレクション を使用しています。
そして ここで説明されているように リフレクションは常にパフォーマンスを低下させます。 (特にDhalvik VM上) onClickListener
を登録するのがより良い方法です。
クリックリスナーを設定するもう1つの方法はXMLを使用することです。タグにAndroid:onClick属性を追加するだけです。
可能であれば、匿名のJavaクラスに対してxml属性「onClick」を使用することをお勧めします。
まず最初に、コードの違いを見てみましょう。
XML属性/ onClick属性
XML部分
<Button
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:id="@+id/button1"
Android:onClick="showToast"/>
Java部分
public void showToast(View v) {
//Add some logic
}
匿名Javaクラス/ setOnClickListener
XML部分
<Button
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"/>
Java部分
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
//Add some logic
}
});
匿名のJavaクラスよりもXML属性を使用する利点は次のとおりです。
もちろん、Xml属性を使用することが常に可能というわけではありません。選択しない理由は次のとおりです。
XML属性を使用することで、クラスの代わりにメソッドを定義するだけでよいので、XMLレイアウトではなくコードを使用して同じことができるかどうか疑問に思いました。
はい、fragment
やactivity
にView.OnClickListener
を実装させることができます
そして、あなたがコードであなたの新しいビューオブジェクトを初期化するとき、あなたは単にmView.setOnClickListener(this);
をすることができます
そしてこれは自動的にあなたのfragment
やactivity
などが持っているonClick(View v)
メソッドを使うようにコード内のすべてのビューオブジェクトを設定します。
どのビューがonClick
メソッドを呼び出したかを区別するために、v.getId()
メソッドにswitchステートメントを使用できます。
この答えは「いいえ、それはコードでは不可能です」と言っている答えとは異なります /
Java 8では、あなたが望むものを達成するためにおそらく メソッドリファレンス を使うことができます。
これがボタンのonClick
イベントハンドラであると仮定します。
private void onMyButtonClicked(View v) {
if (v.getId() == R.id.myButton) {
// Do something when myButton was clicked
}
}
次に、このようにsetOnClickListener()
呼び出しでonMyButtonClicked
インスタンスメソッド参照を渡します。
Button myButton = (Button) findViewById(R.id.myButton);
myButton.setOnClickListener(this::onMyButtonClicked);
これにより、 明示的に 自分で無名クラスを定義することを避けることができます。ただし、Java 8のMethod Referenceは実際には単なる構文上の糖であることを強調しなければなりません。これは実際には匿名クラスのインスタンスをあなたに代わって作成します(ちょうどラムダ式が行ったように)、それであなたがあなたのイベントハンドラの登録抹消に来たときにラムダ式スタイルのイベントハンドラが適用されるのと同様の注意。この article はそれを本当にいい説明しています。
PS。 AndroidでJava 8言語機能を実際にどのように使用できるかについて興味がある人にとっては、これは retrolambda libraryの好意によるものです。
Add Button in xml and give onclick attribute name that is the name of Method.
<!--xml --!>
<Button
Android:id="@+id/btn_register"
Android:layout_margin="1dp"
Android:onClick="addNumber"
Android:text="Add"
/>
Button btnAdd = (Button) findViewById(R.id.mybutton); btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addNumber(v);
}
});
Private void addNumber(View v){
//Logic implement
switch (v.getId()) {
case R.id.btnAdd :
break;
default:
break;
}}
Ruivoの答えを支持します。AndroidのXML onclickで使用できるようにするには、メソッドを "public"として宣言する必要があります - 私はAPI Level 8(minSdk ...)から16(targetSdk ...)までをターゲットとするアプリを開発しています。
私は自分のメソッドをプライベートとして宣言していましたが、エラーが発生しました。パブリックとして宣言するだけでうまくいきます。
Android:onClick
XMLはクリックを処理する便利な方法のように思えますが、setOnClickListener
の実装はonClickListener
を追加する以外にも何か追加のことをします。確かに、ビュープロパティclickable
をtrueに設定します。
ほとんどのAndroid実装では問題にならないかもしれませんが、phoneのコンストラクタによると、buttonは常にclickable = trueに設定されていますが、一部の電話モデルの他のコンストラクタはButton以外のビューではデフォルトのclickable = falseを設定します。
そのため、XMLを設定するだけでは十分ではなく、ボタン以外にAndroid:clickable="true"
を追加するために常に考慮する必要があります。デフォルトがclickable = trueで、このXML属性を設定するのを忘れた場合実行時に問題に気付くが、それがあなたの顧客の手に渡る時には、市場からのフィードバックを得るだろう!
さらに、proguardがどのように難読化してXML属性とクラス・メソッドの名前を変更するかについては絶対にわからないため、100%安全ではないため、いつの日かバグが発生することはありません。
それで、あなたが問題を抱えたくないし、それについて考えたくないのであれば、setOnClickListener
またはButterKnifeのようなライブラリをアノテーション@OnClick(R.id.button)
で使うほうが良いです。
このようなクリックイベントを追加したいとしましょうmain.xml
<Button
Android:id="@+id/btn_register"
Android:layout_margin="1dp"
Android:layout_marginLeft="3dp"
Android:layout_marginTop="10dp"
Android:layout_weight="2"
Android:onClick="register"
Android:text="Register"
Android:textColor="#000000"/>
Javaファイルでは、このようなメソッドを書く必要があります。
public void register(View view) {
}
これを行う最良の方法は、次のコードを使用することです。
Button button = (Button)findViewById(R.id.btn_register);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do your fancy method
}
});
このコードをxmlファイルで書いています...
<Button
Android:id="@+id/btn_register"
Android:layout_margin="1dp"
Android:layout_marginLeft="3dp"
Android:layout_marginTop="10dp"
Android:layout_weight="2"
Android:onClick="register"
Android:text="Register"
Android:textColor="#000000"/>
そしてこのコードを断片的に書く...
public void register(View view) {
}