106

在非 Java 和非 Android 领域有扎实的经验,我正在学习 Android。

我对不同的领域有很多困惑,其中之一是如何处理按钮点击。至少有 4 种方法(!!!),它们在这里简要列出

出于一致性目的,我将列出它们:

  1. 在活动中拥有类的成员View.OnClickListener并将其分配给将处理活动方法onClick中的逻辑的实例。onCreate

  2. 在 'onCreate' 活动方法中创建 'onClickListener' 并使用 setOnClickListener 将其分配给按钮

  3. 在活动本身中实现“onClickListener”并将“this”指定为按钮的侦听器。对于活动按钮很少的情况,应分析按钮 ID 以执行正确按钮的“onClick”处理程序

  4. 在实现“onClick”逻辑的活动上拥有公共方法,并将其分配给活动 xml 声明中的按钮

问题一:

这些都是方法吗,还有其他选择吗?(我不需要任何其他,只是好奇)

对我来说,最直观的方法是最新的方法:它需要输入的代码最少,并且可读性最高(至少对我而言)。

虽然,我没有看到这种方法被广泛使用。使用它有什么缺点?

问题2:

这些方法的优缺点是什么?请分享您的经验或良好的链接。

欢迎任何反馈!

PS我已经尝试谷歌并为这个主题找到一些东西,但我发现的唯一东西是描述“如何”做到这一点,而不是它为什么好或坏。

4

10 回答 10

158

问题1:不幸的是,你说的最直观的那个是Android中使用最少的。据我了解,您应该将 UI(XML)和计算功能(Java 类文件)分开。它还使调试更容易。以这种方式阅读和思考 Android imo 实际上要容易得多。

问题2:我相信主要使用的两个是#2和#3。我将使用 Button clickButton 作为示例。

2

是匿名类的形式。

Button clickButton = (Button) findViewById(R.id.clickButton);
clickButton.setOnClickListener( new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ***Do what you want with the click here***
            }
        });

这是我最喜欢的,因为它在使用 findViewById 设置按钮变量的位置旁边有 onClick 方法。与此 clickButton 按钮视图相关的所有内容都位于此处,这看起来非常整洁。

我的同事评论的一个缺点是,假设您有许多需要 onclick 监听器的视图。你可以看到你的 onCreate 会变得很长。所以他喜欢用:

3

假设你有 5 个 clickButtons:

确保您的 Activity/Fragment 实现 OnClickListener

// in OnCreate

Button mClickButton1 = (Button)findViewById(R.id.clickButton1);
mClickButton1.setOnClickListener(this);
Button mClickButton2 = (Button)findViewById(R.id.clickButton2);
mClickButton2.setOnClickListener(this);
Button mClickButton3 = (Button)findViewById(R.id.clickButton3);
mClickButton3.setOnClickListener(this);
Button mClickButton4 = (Button)findViewById(R.id.clickButton4);
mClickButton4.setOnClickListener(this);
Button mClickButton5 = (Button)findViewById(R.id.clickButton5);
mClickButton5.setOnClickListener(this);


// somewhere else in your code

public void onClick(View v) {
    switch (v.getId()) {
        case  R.id.clickButton1: {
            // do something for button 1 click
            break;
        }

        case R.id.clickButton2: {
            // do something for button 2 click
            break;
        }

        //.... etc
    }
}

正如我的同事解释的那样,这种方式在他看来更整洁,因为所有 onClick 计算都在一个地方处理,而不是拥挤 onCreate 方法。但我看到的缺点是:

  1. 自己的看法,
  2. onClick 方法使用的任何其他可能位于 onCreate 中的对象都必须成为一个字段。

如果您想了解更多信息,请告诉我。我没有完全回答你的问题,因为这是一个很长的问题。如果我找到一些网站,我会扩展我的答案,现在我只是提供一些经验。

于 2013-02-08T23:44:24.157 回答
11

#1当布局上有未生成的按钮(但显然是静态的)时,我经常使用最后一个。

如果您在实践和业务应用程序中使用它,请在此处特别注意,因为当您使用ProGuard 之类的源混淆器时,您需要在您的活动中将这些方法标记为不被混淆。

要使用这种方法归档某种编译时安全性,请查看Android Lint示例)。


#2所有方法的优缺点几乎相同,教训应该是:

使用对您来说最合适或感觉最直观的东西。

如果您必须将相同分配OnClickListener给多个按钮实例,请将其保存在类范围(#1)中。如果您需要一个简单的按钮侦听器,请进行匿名实现:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Take action.
    }
});

我倾向于不在OnClickListener活动中实现,这有时会有点令人困惑(尤其是当您实现多个其他事件处理程序并且没有人知道this都在做什么时)。

于 2013-02-08T23:29:34.610 回答
8

我更喜欢选项 4,但它对我来说很直观,因为我在 Grails、Groovy 和 JavaFX 方面做了太多工作。视图和控制器之间的“魔术”连接是普遍的。很好地命名方法很重要:

在视图中,将 onClick 方法添加到按钮或其他小部件:

    android:clickable="true"
    android:onClick="onButtonClickCancel"

然后在类中,处理方法:

public void onButtonClickCancel(View view) {
    Toast.makeText(this, "Cancel pressed", Toast.LENGTH_LONG).show();
}

再次,清楚地命名方法,无论如何你都应该做的事情,维护成为第二天性。

一大优势是您现在可以为该方法编写单元测试。选项 1 可以做到这一点,但 2 和 3 更难。

于 2015-12-19T17:44:32.453 回答
4

最常用的方式是匿名声明

    Button send = (Button) findViewById(R.id.buttonSend);
    send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // handle click
        }
    });

您也可以创建 View.OnClickListener 对象并稍后将其设置为按钮,但您仍然需要覆盖 onClick 方法,例如

View.OnClickListener listener = new View.OnClickListener(){
     @Override
        public void onClick(View v) {
            // handle click
        }
}   
Button send = (Button) findViewById(R.id.buttonSend);
send.setOnClickListener(listener);

当您的活动实现 OnClickListener 接口时,您必须在活动级别覆盖 onClick(View v) 方法。然后您可以将此活动作为按钮的侦听器,因为它已经实现了接口并覆盖了 onClick() 方法

public class MyActivity extends Activity implements View.OnClickListener{


    @Override
    public void onClick(View v) {
        // handle click
    }


    @Override
    public void onCreate(Bundle b) {
        Button send = (Button) findViewById(R.id.buttonSend);
        send.setOnClickListener(this);
    }

}

(恕我直言)当多个按钮具有相同的处理程序时使用的第 4 种方法,您可以在活动类中声明一个方法并将此方法分配给 xml 布局中的多个按钮,您也可以为一个按钮创建一个方法,但在这种情况下我更喜欢在活动类中声明处理程序。

于 2013-02-08T23:32:27.897 回答
2

为了使问题2更容易,您可以使用像这样的lambda方法来节省变量内存并避免在视图类中上下导航

//method 1
findViewById(R.id.buttonSend).setOnClickListener(v -> {
          // handle click
});

但是如果您希望在方法中一次将点击事件应用于您的按钮。

你可以利用@D的问题3。特兰回答。但不要忘记用View.OnClickListener.

在其他正确使用问题#3

于 2018-05-08T10:18:41.610 回答
1

选项 1 和 2 涉及使用内部类,这会使代码变得混乱。选项 2 有点混乱,因为每个按钮都会有一个侦听器。如果您的按钮数量很少,这没关系。对于选项 4,我认为这将更难调试,因为您将不得不返回和第四个 xml 和 java 代码。当我必须处理多个按钮点击时,我个人使用选项 3。

于 2013-02-08T23:29:37.317 回答
1

我的示例,在 Android Studio 2.1 中测试

在xml布局中定义按钮

<Button
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Java脉动检测

Button clickButton = (Button) findViewById(R.id.btn1);
if (clickButton != null) {
    clickButton.setOnClickListener( new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            /***Do what you want with the click here***/
        }
    });
}
于 2016-08-03T16:39:09.423 回答
0

问题#1 - 这些是处理视图点击的唯一方法。

问题#2 -
选项#1/选项#4 - 选项#1 和选项#4 之间没有太大区别。我看到的唯一区别是在一种情况下活动是实现 OnClickListener,而在另一种情况下,会有一个匿名实现。

选项#2 - 在此方法中将生成一个匿名类。这种方法有点麻烦,因为如果你有多个按钮,你需要多次这样做。对于匿名类,您必须小心处理内存泄漏。

选项#3 - 不过,这是一种简单的方法。通常,程序员在编写任何方法之前都尽量不使用它,因此这种方法没有被广泛使用。您会看到大多数人使用 Option#4。因为它在代码方面更干净。

于 2013-02-08T23:29:24.227 回答
0

第 1 步:创建 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btnClickEvent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me" />
</LinearLayout>

第 2 步:创建 MainActivity:

package com.scancode.acutesoft.telephonymanagerapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {

    Button btnClickEvent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnClickEvent = (Button) findViewById(R.id.btnClickEvent);
        btnClickEvent.setOnClickListener(MainActivity.this);

    }

    @Override
    public void onClick(View v) {
        //Your Logic
    }
}

快乐编码!

于 2016-04-18T10:44:36.947 回答
0

还有一些以各种库的形式提供的选项,可以使使用过其他 MVVM 框架的人非常熟悉这个过程。

https://developer.android.com/topic/libraries/data-binding/

显示了一个官方库的示例,它允许您像这样绑定按钮:

<Button
    android:text="Start second activity"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:onClick="@{() -> presenter.showList()}"
/>
于 2018-06-04T01:55:43.483 回答