Android onClickListener实施最佳做法

时间:2016-05-03 20:52:43

标签: java android event-handling

有四种方法可以将onClickListener添加到可点击的视图(例如按钮):

  1. 在布局文件中设置onClick属性,该属性指向活动中的方法
  2. 创建一个匿名内部类
  3. 将onClickListener分配给私有成员变量。
  4. 让Activity上下文实现onClickListener接口。
  5. 所以我的问题是,你如何选择其中一种实现技术而不是另一种?根据某些条件是否有最佳实践,还是仅仅是程序员偏好的问题?

3 个答案:

答案 0 :(得分:4)

这里我们使用所谓的回调模式。

public class Button {
    private Callback callback;

    public Button(Callback callback) {
        this.callback = callback;
    }

    public void update() {
        // Check if clicked..
        callback.onClick(this);
    }

    public interface Callback {
        public void onClick(Button Button);
    }
}


Button b = new Button(new Callback() {
    @Override
    public void onClick(Button b) {
        System.out.println("Clicked");
    }
});

在我们的例子中,onClick处理程序实现了View.OnClickListener接口。

关键点:

  • 与活动/片段的一致性;
  • 访问活动/片段成员;
  • 可读性;
  • @Michael Krause memory leaks提出了另一个好处;

1)XML文件中的属性只能用于活动,因为 @Karakuri 提到它使用慢的反射。

2)匿名内部类具有访问封闭类成员的特殊规则(检查[1][2])。在某些情况下可能发生内存泄漏(例如使用AsyncTask,Handlers进行线程处理)。

3)在这里,您可以完全访问封闭类的成员。

4)是3d的变体。

可读性取决于您的处理程序大小,小逻辑可以内联,但对于较大的代码块,请考虑3d和4th。

答案 1 :(得分:2)

我从不使用onClick属性,因为它将布局与特定的Activity绑定(它必须通过反射找到方法)。它不适用于碎片。

选项2和3实际上是相同的。如果您想将私有成员用作多个视图的OnClickListener,则选项3可能更有利。

选项4接近选项3.一个关键的区别是它改变了类声明,因此如果保持类声明不受接口实现的影响很重要(或者你可能需要保持二进制兼容性)某种情况),您可能不想使用此选项。

我的建议是避免使用选项1,并选择最符合您代码风格的选项。您也不需要在代码中的每个位置使用相同的方法。

答案 2 :(得分:0)

使用OnClickListener有四种方法。

第一种方式

要在方法调用站点中定义OnClickListener

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = findViewById(R.id.myButton);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // do something
            }
        });
    }
}  

避免这种情况的第一个原因是因为它使onCreate方法变得混乱。当您要从多个视图观察点击事件时,这一点变得更加明显。
避免这种情况的下一个原因是,如果多个按钮应该执行相同操作,则它不会促进代码重用。

第二种方式

第二种方法与第一种几乎相同,除了在类中分配了对field的实现。

public class MainActivity extends AppCompatActivity {

    private View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // do something
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = findViewById(R.id.myButton);
        button.setOnClickListener(clickListener);
    }
}  

这种方法与第一种方法几乎相同,唯一的优点是该方法可以重用于多个按钮。

第三种方式

这种方法是声明一个内部类来实现OnClickListener。如果将其多次使用,最好将实例定义为字段。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = findViewById(R.id.myButton);
        button.setOnClickListener(new ButtonClick());
    }

    class ButtonClick implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            // do something
        }
    }
}  

这种方式的优点是它有助于组织代码。您可以轻松地折叠此内部类,而不必理会它,直到需要查看它为止。
另一个很好的理由是,它可以在公共类中打开并在其他应用程序区域中重用。

第四种方式

第四种方法是使用Activity来实现OnClickListener

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button button = findViewById(R.id.myButton);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // do something
    }
}  

这种方法的第一个缺点是在Activity中创建了一个公共方法,因此在调用this时应该通过setOnClickListener活动。
避免这种方式的第二个原因是,如果添加了另一个按钮,则应确定单击了哪个按钮。然后,您应该使用switch()if()语句。之所以无法执行,是因为每次点击都会浪费一个或几个循环。
这种方式的最后一个缺点是难以组织课程。在示例中,您有一个实现多个接口的活动。突然之间,这些接口中的所有方法都交织在一起,在将方法添加到某些接口后,这一点变得更加明显。同样,现在您也无法使用名为onClick的方法添加接口。

这两种方法之间有些区别,但是您应该根据自己的代码和需求选择方式