Java 在 android 中实现 View.OnClickListener 的最佳方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30082892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:05:49  来源:igfitidea点击:

Best way to implement View.OnClickListener in android

javaandroid

提问by Sarthak Mittal

Suppose we have an Activity with a lot of views on which OnClickListeneris to be registered.

假设我们有一个 Activity 有很多OnClickListener要注册的视图。

The most common way to implement this is to let the Activity-Subclass implement the OnClickListener, something like this:

最常见的实现方式是让 Activity-Subclass 实现 OnClickListener,如下所示:

public class ActivityMain extends Activity implements View.OnClickListener
{   
    @Override
    public void onClick(View view)
    {
        switch (view.getId())
        {
            //handle multiple view click events
        }
    }
}

The way i like to implement it is to create a private class inside the Activity-Subclass and let that inner class implement the OnClickListener:

我喜欢实现它的方式是在 Activity-Subclass 中创建一个私有类,并让该内部类实现 OnClickListener:

public class ActivityMain extends Activity implements View.OnClickListener
{
    private class ClickListener implements View.OnClickListener
    {   
        @Override
        public void onClick(View view)
        {
            switch (view.getId())
            {
                //handle multiple view click events
            }
        }
    }
}

This way the code seems more organized and easy to maintain.

这样,代码看起来更有条理且易于维护。

Moreover, talking about "Is-a", "Has-a" relationships, the latter seems to be a good practice because now the Activity-Subclass would have a "Has-a" relationship with the ClickListener. While in the former method we would be saying that Our Activity-Subclass "Is-a" ClickListener, which ain't completely true.

此外,谈到“Is-a”、“Has-a”关系,后者似乎是一个很好的做法,因为现在 Activity-Subclass 将与 ClickListener 具有“Has-a”关系。而在前一种方法中,我们会说我们的 Activity-Subclass “Is-a” ClickListener,这并不完全正确。

Note that, i am not concerned with the memory overhead the latter would cause.

请注意,我不关心后者会导致的内存开销。

Also, adding onClick tag in xml is completely out of question.

另外,在 xml 中添加 onClick 标签是完全没有问题的。

So, what really is the best way to implement a ClickListener?

那么,真正实现 ClickListener 的最佳方法是什么?

Please don't suggest any libraries like RoboGuice or ButterKnife etc.

请不要推荐任何库,如 RoboGuice 或 ButterKnife 等。

UPDATE:

更新:

I would like to share the approach I finally adopted.

我想分享我最终采用的方法。

I directly implement the listener in Activity/Fragment.

我直接在Activity/Fragment中实现了监听器。

As far as OOP design is concerned. The "HAS-A"approach doesn't offers any practical benefits and even takes up more memory. Considering the amount of nested classes(and the memory overhead) we will be creating for every similar listener we implement, this approach should clearly be avoided.

就 OOP 设计而言。在“HAS-A”的做法并没有提供所有的实际利益,甚至占用更多的内存。考虑到我们将为我们实现的每个类似侦听器创建的嵌套类的数量(和内存开销),显然应该避免这种方法。

采纳答案by kamal vaid

First, there is no best practice defined by Android regarding registering click listeners. It totally depends on your use case.

首先,Android 没有定义关于注册点击监听器的最佳实践。这完全取决于您的用例。

Implementing the View.OnClickListenerinterface to Activity is the way to go. As Android strongly recommends interface implementation over and over again whether it is an Activity or Fragment.

实现View.OnClickListenerActivity的接口是要走的路。由于Android强烈建议一遍又一遍地实现接口,无论是Activity还是Fragment。

Now as you described :

现在正如你所描述的:

public class ActivityMain extends Activity implements View.OnClickListener
{
    private class ClickListener implements View.OnClickListener
    {   
        @Override
        public void onClick(View view)
        {
            switch (view.getId())
            {
                //handle multiple view click events
            }
        }
    }
}

This is your approach. Now it is your way of implementation and there is nothing wrong with this if you are not concerned with memory overhead. But what's the benefit of creating the inner class and implementing the View.OnClickListenerif you can simply implement that in the main class which can also lead to the code clarity and simplicity that you need.

这是你的方法。现在这是您的实现方式,如果您不关心内存开销,这没有任何问题。但是,View.OnClickListener如果您可以在主类中简单地实现它,那么创建内部类并实现它有什么好处,这也可以导致您需要的代码清晰和简单。

So it just a discussion rather getting the best possible solution of implementing the View.OnClickListenerbecause if you go with the practical point of everyone, you will go for a solution which is simple and memory efficient.

所以这只是一个讨论,而不是获得实现View.OnClickListener的最佳解决方案,因为如果您遵循每个人的实际观点,您将寻求一个简单且内存高效的解决方案。

So I would prefer the conventional way. It keeps things simple and efficient. Check the code below:

所以我更喜欢传统的方式。它使事情变得简单而高效。检查下面的代码:

@Override
public void onClick(View view)
{
    switch (view.getId())
    {
        //handle multiple view click events
    }
}

P.S : Your approach will definitely increase lines of code :P ;)

PS:你的方法肯定会增加代码行数:P;)

回答by cyroxis

I have found using Butterknifemakes for clean code. And because it uses code generation (not reflections) it has little performance overhead.

我发现使用Butterknife可以编写干净的代码。而且因为它使用代码生成(而不是反射),所以它的性能开销很小。

public class ActivityMain extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      ButterKnife.inject(this);
  }

  @OnClick(R.id.button_foo)
  void onFoodClicked() {
    // Do some foo
  }

  @OnClick(R.id.button_bar)
  void onBarClicked() {
    // do some bar
  }
}

回答by Jorge Mendez

For this particular case I'd say that maintain a single instance of a OnClickListener is the best approach for you. You will have a "Has-a" relationship and won't need to create several instances since you are handling the behavior using the view id in the onClick(View view)callback.

对于这种特殊情况,我会说维护 OnClickListener 的单个实例对您来说是最好的方法。您将拥有“Has-a”关系并且不需要创建多个实例,因为您正在使用onClick(View view)回调中的视图 ID 处理行为。

public class ActivityMain extends Activity implements View.OnClickListener {

    private View.OnClickListener mClickListener = new View.OnClickListener() {   
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                //handle multiple view click events
            }
        }
    };

}

回答by Charles Durham

Your ClickListeneris an inner non-static class the coupling of this 'has-a' is no different than if your class Activityimplemented View.OnClickListener. This is because your inner ClickListenerrequires an instance of ActivityMainand really can't be reused. I would argue that you're over engineering and aren't actually gaining anything.

ClickListener是一个内部非静态类,这个“has-a”的耦合与你的类Activity实现的没有什么不同View.OnClickListener。这是因为您的内部ClickListener需要一个实例,ActivityMain并且确实无法重用。我会争辩说,你在工程上并没有真正获得任何东西。

EDIT: To answer your question I like to have anonymous View.OnClickListenerfor each widget. I think this creates the best separation of logic. I also have methods like setupHelloWorldTextView(TextView helloWorldTextView);where I put all my logic related to that widget.

编辑:为了回答你的问题,我喜欢View.OnClickListener为每个小部件匿名。我认为这创造了最好的逻辑分离。我也有一些方法,比如setupHelloWorldTextView(TextView helloWorldTextView);我把所有与该小部件相关的逻辑放在那里。

回答by Asif Mujteba

First approach is better than the other because thats why View.OnClickListeneris an Interfaceinstead of an abstract class. besides the later might leak in various situations since you are using a non-static inner class.

第一种方法比另一种更好,因为这就是为什么View.OnClickListener是一个Interface而不是abstract class. 除了后者可能会在各种情况下泄漏,因为您使用的是非静态内部类。

回答by Farbod Salamat-Zadeh

I use button.setOnClickListener(this);where my Activityimplements View.OnClickListener, and then get the ID of the Buttonin a separate method. See below for an example:

我使用button.setOnClickListener(this);where my Activityimplements View.OnClickListener,然后Button在单独的方法中获取 的 ID 。请参阅下面的示例:

public class MyActivity extends ActionBarActivity implements View.OnClickListener {

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

        ...

        Button myFirstButton = (Button) findViewById(R.id.YOUR_FIRST_BUTTON);
        myFirstButton.setOnClickListener(this);

        Button mySecondButton = (Button) findViewById(R.id.YOUR_SECOND_BUTTON);
        mySecondButton.setOnClickListener(this);

        ...

    }

    ...

    @Override
    public void onClick(View v) {
        Button b = (Button) v;
        switch(b.getId()) {
            case R.id.YOUR_FIRST_BUTTON:
                // Do something
                break;
            case R.id.YOUR_SECOND_BUTTON:
                // Do something
                break;
            ...
        }
    }

    ...

}

回答by Sharp Edge

First of all lets get the basics clear here..

首先,让我们在这里弄清楚基础知识..

By implementing an Interface, your class doesn't become that.. like you said:

通过实现接口,你的类不会变成那样......就像你说的:

"Our Activity-Subclass "Is-a" ClickListener, which ain't completely true."

“我们的活动子类“是”ClickListener,这并不完全正确。”

Your class can only have "Is-a" relationship if it extends, in this case an Activity. Implementing an interface means that it can behave like what interface has set its contract.

您的类只有在扩展时才能具有“Is-a”关系,在本例中为Activity. 实现一个接口意味着它的行为就像接口设置了它的契约一样。

An Example:

一个例子:

class Peter extends Human .. means Peter is a Human..

class Peter extends Human .. 意味着 Peter 是一个人类..

class Peter can also implement programmer, musician, husband etc means Peter can behave as the above.

类 Peter 还可以实现程序员、音乐家、丈夫等,这意味着 Peter 可以像上面那样表现。

As for best practice, you could make an entirely separate class which implements OnClickListenerlike this:

至于最佳实践,您可以创建一个完全独立的类,其实现OnClickListener如下:

class MyListener implements View.OnClickListener{

  @Override
public void onClick(View view) {
        // do whatever you want here based on the view being passed
    }

}

And in your main Activityyou could instantiate MyListenerand call onClick()and pass your view in it:

在您的主要内容中,Activity您可以实例化MyListener并调用onClick()并在其中传递您的视图:

MyListener listener = new MyListener();

Button b = null;

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

    button = (Button)findViewById(R.id.button);
    listener.onClick(button);
   }

回答by Hardik Parmar

simply you using like not implements subclass or not handle a click event just do like this way .

只是您使用 like not 实现子类或不处理单击事件就这样做。

android.view.View.OnClickListener method_name = new android.view.View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            // put your code .
        }
    };

and handle click event into button ya any type of click event like

并将单击事件处理为按钮 ya 任何类型的单击事件,例如

button_name.setOnClickListener(method_name);

its work very simply Thanks

它的工作非常简单 谢谢

回答by einschnaehkeee

It really depends on what you want to achieve. If you have e.g. a complex functionality with threading, dependencies, etc., I personally like to decouple it completely from the Activity into a separate class XyzAction, that does the heavy stuff, knows about certain Invokers and returns them results, if needed. My Invokers are basically objects, that implement OnClick/OnTouch/etc.Listeners and bind themselves to needed actions. E.g. there could be a LoginInvokerimplementing OnClickListenerfor a Buttonand an ImageViewand also a generic ActionListenerthat gets invoked when a MenuItemis clicked. The Invokerhas update methods for showing progress to the user and the result of the bound action. The action posts updates to its Invokers and can be garbage collected, if all of them die, because it has no connection to the UI.

这实际上取决于您想要实现的目标。如果你有一个复杂的功能,比如线程、依赖等,我个人喜欢把它从 Activity 完全解耦到一个单独的类中XyzAction,它会做一些繁重的事情,知道某些Invokers 并在需要时返回它们的结果。我的Invokers 基本上是实现OnClick/ OnTouch/ 等的对象。Listeners 并将自己绑定到所需的操作上。例如,有可能是一个LoginInvoker实现OnClickListenerButtonImageView,也是一个通用的ActionListener一个时被调用MenuItem被点击。在Invoker具有用于向用户示出的进步和结合作用的结果的更新方法。该操作将更新发布到其Invokers 并且可以被垃圾收集,如果它们都死了,因为它没有连接到 UI。

For less complex actions, I couple them directly to the Android component (i.e. Activity/Feagment/View) and also call them Actions, with the big difference of them implementing the UI callbacks directly.

对于不太复杂的动作,我夫妇与他们直接到Android组件(即Activity/ Feagment/ View),并还呼吁他们Actions,与他们的大的差异直接实现UI回调。

In both cases I declare the actions as members, so I can see on a quick glance what specific actions the Android component supports.

在这两种情况下,我都将操作声明为成员,因此我可以快速浏览一下 Android 组件支持哪些特定操作。

If there's something trivial like "show a Toast if button is pressed", I use anonymous inner classes for the UI callbacks, because you normally don't care that much about them with regards to maintainability.

如果有诸如“按下按钮时显示 Toast”之类的小事,我将匿名内部类用于 UI 回调,因为在可维护性方面您通常不太关心它们。

回答by King of Masses

Here you can create a btnClickListner object and after that you will call that btnCLickLisner object when ever you want to perform the onCLieck actions for buttons..

在这里,您可以创建一个 btnClickListner 对象,之后您将在想要对按钮执行 onCLieck 操作时调用该 btnCLickLisner 对象。

Let us assume, in my activity i have a 5 to 10 buttons and writing each button separate onclick listner is bad idea. So to over come this,we can use like below..

让我们假设,在我的活动中,我有 5 到 10 个按钮,将每个按钮单独编写 onclick 监听器是个坏主意。所以为了解决这个问题,我们可以像下面这样使用..

register your buttons

注册你的按钮

Button button1 = (Button)findViewById(R.id.button1);
Button button2 = (Button)findViewById(R.id.button2);
Button button3 = (Button)findViewById(R.id.button3);
Button button4 = (Button)findViewById(R.id.button4);
Button button5 = (Button)findViewById(R.id.button5);

Here i am setting the onclick listner to my buttons after click

在这里,我在单击后将 onclick 监听器设置为我的按钮

button1.setOnClickListener(btnClickListner);
button2.setOnClickListener(btnClickListner);
button3.setOnClickListener(btnClickListner);
button4.setOnClickListener(btnClickListner);
button5.setOnClickListener(btnClickListner);

Here is the btnClick Listner implementation

这是 btnClick 监听器的实现

View.OnClickListener btnClickListner = new OnClickListener()
    {
  @Override
        public void onClick( View v )
        {
            // TODO Auto-generated method stub
            if( button1.getId() == v.getId() )
            {
                //Do Button1 click operations here

            }
            else if( button2.getId() == v.getId() )
            {

               // Do Button2 click operations here

            }
            else if( button3.getId() == v.getId() )
            {
                 // Do Button3 click operations here

            }
            else if( button4.getId() == v.getId() )
            {
                // Do Button4 click operations here

            }
            else if( button5.getId() == v.getId() )
            {
                // Do Button5 click operations here
            }

        }

     }