【问题标题】:Best practice for defining button events in android在android中定义按钮事件的最佳实践
【发布时间】:2011-09-16 08:35:38
【问题描述】:

我在 XML 中定义了一个 Layout,它由几个 Buttons 组成。

目前我在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
    .....
}

在Button 的onClick 事件中,我启动相机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.. 中重新注册事件是正确的方法吗?还是我做错了什么?因为如果我不重新注册事件,当我点击按钮时不会发生任何事情。

【问题讨论】:

  • 如果它们已经在onCreate() 中设置,您不必在onActivityResult() 中再次设置它们
  • :S 如果我在意图返回主视图时不执行此操作,则单击按钮不会发生任何事情

标签: android button event-handling


【解决方案1】:

为什么不在 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 语句来确定来源。

这样您就可以使用一种方法来处理一个布局中的所有按钮。

更新:
虽然这是一种有效的方法,但我强烈推荐第二种选择。它更干净,更容易维护,尤其是在处理片段时。

【讨论】:

  • 在布局中包含“onClick”在使用片段时效果不佳。请看一下这个 SO 帖子:stackoverflow.com/questions/6091194/…
  • 这也使你的代码难以更改。重命名 xml 中的内容不会影响代码。
  • 一旦您开始使用 Fragments,这几乎是不可能维护的。更好的方法是让片段类实现 OnClickListener 接口。
  • 非常糟糕的做法,使代码很难维护。
  • 当您的应用程序开始变得越来越大时,这将是一种痛苦。一种更简洁且可维护的方法是在 java 代码中定义侦听器。
【解决方案2】:

这是最好的代码方法:

  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 实现依赖于它参考在那里定义的对象运行,您绝对应该使用我建议的方法。

只有当你想在不同的类或活动之间实现通信并将它们分开时,创建类接口才是好的。除此之外,为此创建子类是一种不好的做法。

【讨论】:

    【解决方案3】:

    这是最好的方法

    @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;
             }
    
       }
    };
    

    【讨论】:

      【解决方案4】:

      没有定义最佳实践。这在很大程度上取决于用例。您可以使用 Button 的 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。您可以为每个 Button 分配相同的 onClick 方法,然后简单地根据每个视图决定触发什么操作,或者您可以为每个 Button 设置单独的方法。

      一般来说,我建议不要将一个OnClickListener 用于多个按钮。如果您使用描述性名称,则更容易理解每​​个听众应该做什么,这也是您应该做的。

      【讨论】:

      • 这可行,但知道为什么 v.getId() is not same as R.id.takepic_button` takepic_button 是我在 XML 中设置事件的按钮
      • 我不知道。那是你必须自己去发现的东西。
      • 抱歉,我的错误效果很好,这正是我想要的
      【解决方案5】:

      我喜欢使用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
      }
      

      【讨论】:

        【解决方案6】:

        @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</string
          
        • 在 sample.java 文件中,R.string 中定义的函数将在单击按钮时被调用,它应该类似于

          public void buttonFunction(View view) {
              // do nething u like on the click of the button
          }
          

        【讨论】:

          【解决方案7】:

          您的 Activity 应该实现 OnClickListener,并且您应该在单个 OnCLick() 方法中编写所有按钮的所有事件处理。

          【讨论】:

            【解决方案8】:

            问题是按钮 newPicButton 的对象被创建为本地对象,该对象仅在函数 onCreate 的范围内有效,并且一旦代码退出该函数,垃圾收集器就会为按钮取消分配对象。您需要做的是在任何方法之外声明 newPicButton 对象,然后在 onCreate 方法中为其分配一个侦听器。这将解决您的问题,我希望我已经解释了为什么当您在 onActivityResult 方法中删除 newPicButton 的代码时什么都没有发生:)

            【讨论】:

            • 这正是我的想法和所做的,但即便如此也没有任何反应
            【解决方案9】:

            我知道这是旧的,但如果有人想知道为什么不能从onActivityResult 添加onClickListener,那是因为按钮为空。如果你再次初始化它(就像你在onCreate 中所做的那样),你可以添加监听器。但是请注意,其他所有内容也将为空,因此,例如,如果您从 EditText 获取数据,您还必须对其进行初始化(在 lisneter 中简单检查对象是否为空即可诀窍)。

            【讨论】:

              【解决方案10】:

              我是这样做的:

              1. 在按钮 XML 文件中设置 android:onClick="onClick"。
              2. 在您的 Activity 中实现 View.OnClickListener。
              3. 在 onClick 方法中使用 Switch 键(如下)。

              @Override

              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;
              
                  }
              }
              

              效果很好。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多