web-dev-qa-db-ja.com

androidでボタンイベントを定義するためのベストプラクティス

複数のLayoutsで構成されるButtonがXMLで定義されています。

現在、ボタンに対してイベントハンドラを定義するためにOnCreateメソッドでこれを行っています。

public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button newPicButton = (Button)findViewById(R.id.new_button);
    newPicButton.setOnClickListener(btnListener);
    ..... similarly for other buttons too
    .....
}

ButtononClickイベント内で、カメラIntentを起動して写真を取得し、onActivityResultコールバック内で、イベントハンドラーを再度設定します。 Viewを次のように設定します。

protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{ 
    setContentView(R.layout.main);
    Button newPicButton = (Button)findViewById(R.id.new_button);
    newPicButton.setOnClickListener(btnListener);
    ...similarly for other buttons too
}

私はAndroidに不慣れで、毎回イベントを再定義するこのアプローチは非常に汚いようです。このようなシナリオでボタンイベントハンドラーを定義する上でのベストプラクティスは何かを知りたいです。 。

編集:クラス全体を貼り付ける

public class CameraAppActivity extends Activity 
{
    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button newPicButton = (Button)findViewById(R.id.new_button);
        newPicButton.setOnClickListener(btnListener);
    }

    //---create an anonymous class to act as a button click listener---
    private OnClickListener btnListener = new OnClickListener()
    {

        public void onClick(View v)
        {   
             //Intent newPicIntent = new Intent(v.getContext(), NewPictureActivity.class);
             //startActivityForResult(newPicIntent, 0);
            Intent cameraIntent = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(cameraIntent, 999);
        } 

    };  

    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    {  

        setContentView(R.layout.main);
        Button newPicButton = (Button)findViewById(R.id.new_button);
        newPicButton.setOnClickListener(btnListener);

       //if I comment last two lines nothing happens when I click on button

    }  

主な質問は

setContentView(R.layout.main);
Button newPicButton = (Button)findViewById(R.id.new_button);
newPicButton.setOnClickListener(btnListener);

onActivityResult内でイベントを再登録します。正しいアプローチですか?それとも私は何か間違ったことをしていますか?イベントを再登録しないと、ボタンをクリックしても何も起こらないからです。

66
Haris Hasan

XMLレイアウトでonClickイベントを登録してから、コードで処理してみませんか。これは私がそれをする方法です:

<Button
Android:id="@+id/my_btn"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:text="Click me"
Android:onClick="onBtnClicked">
</Button>

次に、クリックを処理するメソッドを作成します

public void onBtnClicked(View v){
    if(v.getId() == R.id.my_btn){
        //handle the click here
    }
}

または、コード内のアイテムごとにOnClickListenerを個別に設定できます。次に、if/elseまたはswitchステートメントを使用して、Originを決定します。

これにより、1つのレイアウトからすべてのボタンを処理する1つのメソッドを作成できます。

更新:
これは有効なアプローチですが、2番目のオプションを強くお勧めします。特にフラグメントを操作する場合は、よりクリーンで保守が容易です。

64
Marqs

コードを使用した最適なアプローチを次に示します。

  public class MyTest extends Activity implements OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     //... some other code here to init the layout
        Button btn1 = (Button)findViewById(R.id.button1);
        Button btn2 = (Button)findViewById(R.id.button2);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.button1:
                break;
            case R.id.button2:
                break;
        }
    }
}

インターフェースを備えた新しいクラスは、実装を分離したい場合(他の場所で同じクラスコードを使用する場合、別の別のクラスファイルに移動する場合など)にのみ有効ですが、一般的には現在のアクティビティとonClickの実装は、そこで定義されているオブジェクトを参照して実行されることに依存しているため、私が提案するメソッドを必ず使用する必要があります。

クラスインターフェイスの作成は、別々のクラスまたはアクティビティ間の通信を実現し、物事を区別したい場合にのみ有効です。それ以外は、このためのサブクラスを作成するのは悪い習慣です。

39
DArkO

これが最良のアプローチです

@Override
public void onCreate(Bundle savedInstanceState) {
        button1.setOnClickListener(onClickListener);
        button2.setOnClickListener(onClickListener);
        button3.setOnClickListener(onClickListener);
}

private OnClickListener onClickListener = new OnClickListener() {
     @Override
     public void onClick(final View v) {
         switch(v.getId()){
             case R.id.button1:
                  //DO something
             break;
             case R.id.button2:
                  //DO something
             break;
             case R.id.button3:
                  //DO something
             break;
         }

   }
};
12

定義されたベストプラクティスはありません。ユースケースに大きく依存します。ボタンのonClick属性を使用して、XMLレイアウトでそれらを定義できます。

XMLの例:

<!-- Stuff -->
<Button Android:id="@+id/my_button"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="Click Me!"
    Android:onClick="myClickMethod" />

Javaの例:

// stuff
public void myClickMethod(View v) {
    // more stuff
}

そうすれば、OnClickListenerを自分で実装する必要はありません。各ボタンに同じonClickメソッドを割り当ててから、ビューごとにトリガーするアクションを決定するか、ボタンごとに個別のメソッドを設定できます。

一般に、複数のボタンに1つのOnClickListenerを使用することはお勧めしません。わかりやすい名前を使用すると、各リスナーが何をすべきかを理解しやすくなります。

8

Butter Knife :を使用することで、「現代の」DIの方法が好きです。

  1. ビューを宣言する
@InjectView(R.id.buttonAlert) 
Button buttonAlert;
  1. すべての注釈付きリソースを注入する
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.inject(this);
 }
  1. OnClickメソッドに注釈を付けて実装します
@OnClick(R.id.buttonAlert)
public void alertClicked(View v){
    // your logic
}
7
funcoder

@Hasanこれは私が見つけた最高のアプローチであり、毎回完璧に機能します。

  • Layout.xmlで、ボタンのonClickを定義します

                    <Button Android:id="@+id/Button01"          
                        Android:onClick="@string/method" 
                        Android:focusable="true" Android:clickable="true"
                        ">
                    </Button>
    
  • R.stringファイルに次の行を追加します

string name = "method"> buttonFunction

  • Sample.Javaファイルでは、ボタンをクリックするとR.stringで定義された関数が呼び出され、次のようになります。

    public void buttonFunction(View view){//ボタンのクリックで好きなことをする}

2
Nitin

ここに私がそれをした方法があります:

  1. Buttons XMLファイルでAndroid:onClick = "onClick"を設定します。
  2. アクティビティにView.OnClickListenerを実装します。
  3. OnClickメソッドの内部では、スイッチキーを使用します(以下を参照)。

@オーバーライド

public void onClick(View view) {
    Intent intent;
    switch(view.getId()){

        case R.id.home_button:
            //DO something
            intent = new Intent(HashTagActivity.this,MainActivity.class);
            startActivity(intent);
            break;
        case R.id.back_button:
            //DO something
             intent = new Intent(HashTagActivity.this,ClassActivity.class);
            startActivity(intent);
            break;
        case R.id.favorite_button:
            //DO something
            break;
        case R.id.copy_button:
            //DO something

            break;

    }
}

うまくいきます。

これは古いことは知っていますが、なぜonClickListenerからonActivityResultを追加できないのか不思議に思っているなら、それはボタンがヌルだからです。 (onCreateで行ったように)もう一度初期化すると、リスナーを追加できます。ただし、他のすべてもnullになるため、注意してください。たとえば、EditTextからデータを取得する場合は、それも初期化する必要があります(オブジェクトがlisneterがトリックを行います)。

0
Yordan Lyubenov

アクティビティはOnClickListenerを実装し、単一のOnCLick()メソッド内ですべてのボタンのすべてのイベント処理を記述する必要があります。

0
Sujit

問題は、ボタンonPicButtonのオブジェクトが、onCreate関数のスコープ内でのみ有効なローカルオブジェクトとして作成され、その関数が終了するとすぐに、ガベージコレクターがボタンのオブジェクトの割り当てを解除することです。あなたがする必要があるのは、メソッドの外でnewPicButtonオブジェクトを宣言し、onCreateメソッドでそれをリスナーに割り当てることです。これで問題が解決します。onActivityResultメソッドでnewPicButtonのコードを削除しても何も起こらない理由を説明できたらと思います。

0
Nitin