简体   繁体   English

XML onClickListener与程序设计方法的优缺点

[英]Pros and cons of XML onClickListener vs programatic approach

I would like to find which approach is better for binding onClickListener in Android. 我想找到哪种方法更适合在Android中绑定onClickListener

There are several major ways to achieve this. 有几种主要方法可以实现此目的。 We can use android:onClick attribute in XML , a programmatic approach: 我们可以使用XML (一种编程方法)中的android:onClick属性:

   findViewById(R.id.button1).setOnClickListener(
       new View.OnClickListener() {
          @Override
          public void onClick(View v) {
             //Add some logic
          }
       }
   );

And various DataBinding libraries like ButterKnife . 还有各种数据绑定库,例如ButterKnife For the sake of simplicity let's leave the data binding libraries aside and focus on the XML attribute VS programmatic approach. 为了简单起见,我们将数据绑定库放在一边,而将重点放在XML属性VS编程方法上。

In my opinion, the XML attribute is superior for the following reasons: 我认为,由于以下原因,XML属性是优越的:

  1. With the programmatic approach we always have to specify an ID for our elements, but with XML attribute it can be omitted. 使用编程方法,我们总是必须为元素指定ID,但是使用XML属性可以将其省略。
  2. With the programmatic approach class we have to actively search for the element inside of the view ( findViewById portion), but with the XML attribute, Android does it for us. 使用编程方法类,我们必须主动搜索视图内部的元素( findViewById部分),但是使用XML属性,Android会为我们完成此操作。
  3. The programmatic approach class requires at least five lines of code, as we can see, but with the XML attribute, three lines of code are sufficient. 如我们所见,程序化方法类至少需要五行代码,但是使用XML属性,三行代码就足够了。
  4. With the programmatic approach we have to name our method onClick , but with the XML attribute, we can add any name we want, which will dramatically help with the readability of the code. 使用编程方法,我们必须将方法命名为onClick ,但是使用XML属性,我们可以添加所需的任何名称,这将大大有助于代码的可读性。
  5. The XML onClick attribute has been added by Google in the API level 4 release, which means that it is a bit more modern. Google在API级别4版本中添加了XML onClick属性,这意味着它更加现代。 And the new syntax is almost always better. 而且新语法几乎总是更好。

Obviously, we cannot use the XML attribute with Fragments, but as far as the Activities go, it looks like a superior approach to me. 显然,我们不能将XML属性与Fragments一起使用,但是就Activity而言,对我来说,这似乎是一种更好的方法。

That said, in my experience, the programmatic approach seems to be preferred. 就是说,根据我的经验,程序化方法似乎是首选。 Am I missing something? 我想念什么吗?

I prefer much more the programmatic approach for two reasons: 由于两个原因,我更喜欢编程方法:

Centralized management of the click events : in this case you must use the same method to manage all clicks, instead of a custom method that you can change. 点击事件的集中管理 :在这种情况下,您必须使用相同的方法来管理所有点击,而不是可以更改的自定义方法。 Example: 例:

public class ActivityA extends Activity implements View.OnClickListener {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        findViewById(R.id.first).setOnClickListener(this);
        findViewById(R.id.second).setOnClickListener(this);
        findViewById(R.id.third).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.first:
                // Manage click.
                break;

            case R.id.second:
                // Manage click.
                break;

            case R.id.third:
                // Manage click.
                break;
        }
    }
}

Performance : the programmatic approach is more performant than the XML one for two reasons. 性能 :出于两个原因,编程方法比XML方法更具性能。 The first one is that every time that you declare the android:onClick attribute in XML, a new DeclaredOnClickListener will be instantiated. 第一个是每次您以XML声明android:onClick属性时,都会实例化一个新的DeclaredOnClickListener It's more performant to have a shared click listener if you have more than one View in the same tree. 如果同一棵树中有多个View ,则拥有一个共享的Click侦听器会更有效。 The second one is that DeclaredOnClickListener uses reflection internally to invoke your method. 第二个是DeclaredOnClickListener内部使用反射来调用您的方法。

Same pattern across different components : you can't use the XML approach in a Fragment so you must change the way you declare click listener from Activity to Fragment . 跨不同组件的模式相同 :不能在Fragment使用XML方法,因此必须将声明Click监听器的方式从Activity更改为Fragment Instead, if you use the programmatic approach, you apply the same pattern both in Activity and Fragment . 相反,如果您使用编程方法,则可以在ActivityFragment应用相同的模式。

I'll share also my personal experience: in the past, at the first times, I used also the XML approach. 我还将分享我的个人经验:在过去的第一次,我也使用XML方法。 Now, I never use it for a project, because, also if you write more code in the programmatic approach, I think it's more ordered. 现在,我从不将其用于项目,因为,如果您以编程方式编写更多代码,我认为它的顺序也更合理。

Use DataBinding library so that you don't need to call findViewById(int) for each view repeatedly. 使用DataBinding库 ,这样就不必为每个视图重复调用findViewById(int) A public final field will be generated for each View with an ID in the layout. 将为每个在布局中具有ID的视图生成一个公共最终字段。 The binding does a single pass on the View hierarchy, extracting the Views with IDs. 绑定对View层次结构进行一次传递,提取具有ID的View。 This mechanism can be faster than calling findViewById(int) for several Views. 这种机制可能比为多个视图调用findViewById(int)更快。

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

setup clickListener for necessary views as follows. 设置clickListener以获取必要的视图,如下所示。

binding.button1.setOnClickListener(this);
binding.button2.setOnClickListener(this);

Handle all button click events with in the onClick(View) implementation so that you don't need to add individual anonymous listener for each button. onClick(View)实现中处理所有按钮单击事件,因此您无需为每个按钮添加单独的匿名侦听器。 Anonymous inner classes should be avoided where ever possible because anonymous classes will hold an implicit reference to the outer class. 应尽可能避免使用匿名内部类,因为匿名类将隐含对外部类的引用。

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

            case R.id.button2:
               onClickButton2();
                break;


        }
    }

So we can conclude that the programmatic approach with Data binding seems to be preferred. 因此,我们可以得出结论, 采用数据绑定程序设计方法似乎是首选。

Xml approach vs programmatic approach: Xml方法与程序方法:

pros using xml approach 使用xml方法的专业人士

  • on every element you can define a user defined method 您可以在每个元素上定义用户定义的方法
  • user defined method will have a fully qualified name 用户定义的方法将具有完全限定的名称
  • declaring method with fully qualified name improves readability 具有完全限定名称的声明方法可提高可读性

pros using programmatic approach 使用程序化方法的专业人士

  • for every "onclick" event of each element you don't have to define a method 对于每个元素的每个“ onclick”事件,您都无需定义方法
  • in programmatic approach this can be achieved by declaring only one onclick method by overriding View.OnClickListener 以编程方式,这可以通过重写View.OnClickListener仅声明一个onclick方法来实现。

conclusion : It totally depends on developer and requirements- 结论 :这完全取决于开发人员和要求-

if there are too many on click methods in one activity than one can choose programmatic approach as it will be very tedious to follow xml approach and write too many on click methods for every element. 如果一个活动中的单击方法太多,则不能选择编程方法,因为遵循xml方法并为每个元素编写过多的单击方法将非常繁琐。

Also, if the no. 另外,如果没有。 of onclick is not very much in an activity than its a commonsense to use xml approach as there will not be too many methods to write and it will increase readability of code. onclick的活动与其说是使用xml方法的常识,不如说是一项活动,因为它不会编写太多的方法,并且会增加代码的可读性。

xml approach example : xml方法示例

main.xml : main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="92dp"

        android:onClick="clickFunc1"

        android:text="Click me" />
           <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="92dp"

        android:onClick="clickFunc2"

        android:text="Click me" />

</RelativeLayout

MainActivity.java : MainActivity.java

public class MainActivity extends Activity {

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public void clickFunc1(View view){
        Toast.makeText(MainActivity.this, "Button1 Clicked",    Toast.LENGTH_SHORT).show();
    }

    public void clickFunc2(View view){
        Toast.makeText(MainActivity.this, "Button2 Clicked",    Toast.LENGTH_SHORT).show();
    }


}

programmatic approach : 程序化方法

main.xml : main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="92dp"
        android:text="Click me" />
           <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="92dp"
        android:text="Click me" />
           <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="92dp"
        android:text="Click me" />

</RelativeLayout>

MainActivity.java : MainActivity.java

public class MainActivity extends Activity implements View.OnClickListener {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
        findViewById(R.id.button3).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button1:
               Toast.makeText(MainActivity.this, "Button1 Clicked", Toast.LENGTH_SHORT).show();
                break;

            case R.id.button2:
               Toast.makeText(MainActivity.this, "Button2 Clicked", Toast.LENGTH_SHORT).show();
                break;

            case R.id.button3:
              Toast.makeText(MainActivity.this, "Button3 Clicked",  Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM