web-dev-qa-db-ja.com

Android:onClick XML属性はsetOnClickListenerとどのように違うのですか?

私が読んだことから、2つの方法でonClickハンドラをボタンに割り当てることができます。

Publicメソッドの名前をsignaturevoid name(View v)と一緒に使用する場合、またはsetOnClickListenerメソッドを使用してOnClickListenerインターフェースを実装するオブジェクトを渡す場合は、Android:onClick XML属性を使用します。後者はしばしば私が嫌いな(個人的な好み)またはOnClickListenerを実装する内部クラスを定義する匿名クラスを必要とします。

XML属性を使用することで、クラスの代わりにメソッドを定義するだけでよいので、XMLレイアウトではなくコードを使用して同じことができるかどうか疑問に思いました。

379
emitrax

いいえ、それはコードでは不可能です。 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 が好きではないと言うつもりでした。

563

私が一番上の答えを見たとき、私の問題はファンシーメソッドにパラメータ(View v)を置いていないことを私は理解しました:

public void myFancyMethod(View v) {}

Xmlからそれにアクセスしようとするとき、人は使うべきです

Android:onClick="myFancyMethod"/>

誰かに役立つことを願っています。

81
jp093121

Android:onClickはAPIレベル4以降を対象としているため、1.6未満をターゲットにしている場合は使用できません。

72
James

メソッドを公開するのを忘れていないか確認してください。

30
Ruivo

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を使用することです。

これは他の答えで述べられる問題の理由です:

  • コールバックメソッドはpublicにする必要があります Java Class getMethod が使用されるため、publicアクセス指定子を持つ関数のみが検索されます。そうでなければIllegalAccessException例外を処理する準備ができています。
  • FragmentでonClickを使用してButtonを使用している間は、コールバックをActivity :で定義する必要があります。getContext().getClass().getMethod()呼び出しは、現在のコンテキスト(フラグメントの場合はActivity)にメソッド検索を制限します。したがって、methodはFragmentクラスではなくActivityクラス内で検索されます。
  • コールバックメソッドはViewパラメータを受け入れるべきです Java Class getMethodから はパラメータとしてView.classを受け入れるメソッドを検索します。
25
Manish Mulimani

OnClick XML機能を使用する場合は、対応するメソッドに1つのパラメータがあり、そのタイプはXMLオブジェクトと一致する必要があります。

たとえば、 ボタン は、名前文字列:Android:onClick="MyFancyMethod"によってメソッドにリンクされますが、メソッド宣言は次のようになります。...MyFancyMethod(View v) {...

この機能を メニュー項目 に追加しようとしている場合は、XMLファイルでもまったく同じ構文になりますが、メソッドは次のように宣言されます。...MyFancyMethod(MenuItem mi) {...

13
Antoine Lizée

ここには非常に良い答えがありますが、1行追加したいと思います。

XMLのAndroid:onclickでは、Androidはこれを処理するために Javaリフレクション を使用しています。

そして ここで説明されているように リフレクションは常にパフォーマンスを低下させます。 (特にDhalvik VM上) onClickListenerを登録するのがより良い方法です。

11
Krupal Shah

クリックリスナーを設定するもう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属性を使用する利点は次のとおりです。

  • 匿名Javaクラスでは、常に要素にidを指定する必要がありますが、XML属性ではidを省略できます。
  • 匿名Javaクラスでは、ビュー内の要素(findViewById部分)を積極的に検索する必要がありますが、XML属性のAndroidではそれが可能です。
  • ご覧のとおり、匿名Javaクラスには少なくとも5行のコードが必要ですが、XML属性の場合は3行のコードで十分です。
  • Anonymous Javaクラスでは、メソッドに "onClick"という名前を付ける必要がありますが、XML属性では、任意の名前を追加できます。これは、コードの読みやすさを大幅に向上させるのに役立ちます。
  • Xmlの "onClick"属性は、APIレベル4のリリース中にGoogleによって追加されました。つまり、それはもう少し現代的な構文であり、現代的な構文はほとんど常に優れています。

もちろん、Xml属性を使用することが常に可能というわけではありません。選択しない理由は次のとおりです。

  • フラグメントを扱っているのならonClick属性はアクティビティにしか追加できないため、フラグメントがある場合は匿名クラスを使用する必要があります。
  • OnClickリスナを別のクラスに移動したい場合(おそらく非常に複雑で、かつ/またはアプリケーションのさまざまな部分でそれを再利用したい場合)、xml属性を使用したくないでしょう。どちらでも。
5
Bestin John

XML属性を使用することで、クラスの代わりにメソッドを定義するだけでよいので、XMLレイアウトではなくコードを使用して同じことができるかどうか疑問に思いました。

はい、fragmentactivityView.OnClickListenerを実装させることができます

そして、あなたがコードであなたの新しいビューオブジェクトを初期化するとき、あなたは単にmView.setOnClickListener(this);をすることができます

そしてこれは自動的にあなたのfragmentactivityなどが持っているonClick(View v)メソッドを使うようにコード内のすべてのビューオブジェクトを設定します。

どのビューがonClickメソッドを呼び出したかを区別するために、v.getId()メソッドにswitchステートメントを使用できます。

この答えは「いいえ、それはコードでは不可能です」と言っている答えとは異なります /

4
CQM

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の好意によるものです。

4
onelaview
   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;
    }}
4
jeet parmar

Ruivoの答えを支持します。AndroidのXML onclickで使用できるようにするには、メソッドを "public"として宣言する必要があります - 私はAPI Level 8(minSdk ...)から16(targetSdk ...)までをターゲットとするアプリを開発しています。

私は自分のメソッドをプライベートとして宣言していましたが、エラーが発生しました。パブリックとして宣言するだけでうまくいきます。

3
Waqas Hasan

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)で使うほうが良いです。

1
Livio

このようなクリックイベントを追加したいとしましょう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) {
}
1
nazrul islam

How Android:onclick xml attribute works in Android

androidのメソッドの名前を使用するだけです:onClick属性の値。メソッド名の前にpublicキーワードが使用されていることを確認してください。

Android onClick XMLの例

1
c49

これを行う最良の方法は、次のコードを使用することです。

 Button button = (Button)findViewById(R.id.btn_register);
 button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //do your fancy method
            }
        });
0
Katarina Dabo

このコードを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) {
}
0
user2786249