在Android中处理事件的最佳方法

14

我知道这似乎是一个重复的问题,但我真的找不到一个关于相关主题的好答案。

关于如何处理ButtonOnClick事件有很多问题。
以下是我遇到的一些选项:

1-在OnCreate方法中以编程方式定义监听器:

button.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        //do stuff
    }
});

2 - 在XML中设置android:OnClick属性:

<Button android:id="@+id/btnDelete"
    ...
    android:OnClick="btnDelete_OnClick"/>

3 - 在Activity类上实现OnClickListener接口,并将自引用传递给按钮:

public class MainActivity extends Activity implements OnClickListener{
    @Override
    public void onClick(View v) {
        //do stuff
    }

    protected void onCreate(Bundle savedInstanceState) {
        ...
        button.setOnClickListener(this);
    }
}

4 - 创建一个类型为OnClickListener的字段:

private OnClickListener onClickHandler = new OnClickListener(){

    @Override
    public void onClick(View v) {
        //stuff
    }
};

protected void onCreate(Bundle savedInstanceState) {
    ...
    button.setOnClickListener(onClickHandler);
}

当涉及到ButtonOnClick事件时,我总是更喜欢在XML中定义它,这样更加清晰。但是其他事件如来自ListViewOnItemClick或者TimePickerDialogOnTimeSet呢?我没有看到可以在XML上设置的属性。我认为实现Listener接口是一个相当干净的解决方案,但这意味着我只能实现一次,如果我有两个相同的视图,则必须在同一个地方处理它们的事件。如果我使用选项2或4,则可能在处理来自UI不同视图的多个事件时会变得非常混乱。我想看到其他人对此问题的看法,是否有其他事件处理实现的选择?是否真的存在可以定义为更好的替代方案,还是每个程序员都有个人偏好?

为了遵循Java术语,n.4不是局部变量而是字段。无论如何,我个人更喜欢样式n.4,但我不知道它是否是内存的最佳选项。 - vault
这不是“局部字段”,只是一个字段 :D - vault
我明白了,@vault。那么再次感谢你:)。 - Mateus Schneiders
5个回答

3

让我逐个解释:

情况#1 这种方式将会随着创建按钮而创建匿名类(每个按钮都需要新的监听器),不易读懂且成本高。

情况#2 实际上,如果您查看其后面的代码,您会发现它使用反射查找回调的监听器(方法),这样不易读懂,还会使其他开发人员感到困惑。

情况#3 这种方式很难导航,因为您无法确定当前按钮使用的监听器类型(我知道eclipse会突出显示指向的方法this,但是对于大型代码来说,我认为很难找到)。

情况#4 我认为这是实现监听器的最佳方式,易于导航,更易读,一个监听器可以处理所有相关事件(并且使用eclipse,只需ctrl+click即可转到监听器),所以我推荐使用这种方式(在工作中仅使用此方法)。

希望这能有所帮助。


1
  1. 如果我只在类中有一个或两个监听器,比如listview的onItemClickListener,我喜欢使用这种方法。但是当有多个视图时,它确实变得非常混乱。

  2. 我根本不使用android:onClick,因为我喜欢将我的代码放在我的代码中。

  3. 当我需要处理几个视图时,我喜欢这种方法。然而,我仍然喜欢保持我的onClick()代码简洁。它通常会成为一个id的switch,类似的视图组调用其他方法来处理,例如handleDownVote()或类似的方法。这样,所有我的主要“处理”调用都在一个地方完成。

  4. 我不知道人们会这样做。我想它比#3更好地能够分组相似的视图,但我从来没有真正考虑过。也许我有时会试一试。

归根结底,这是一个高度主观的问题,因为没有真正的“正确”或“优化”的方法。正如您所看到的,到目前为止每个答案都不同。无意冒犯,但建议关闭投票。


0

处理按钮的OnClick事件的最佳方法取决于以下几点:

1. 按钮数量。

答案:如果您只有一个按钮,可以使用创建匿名类的第一种方法。但是,如果您有多个按钮,则不应创建多个匿名onClicklisteners,而应选择其他选项。

2. 内存优化

答案:如果您在Activity类上实现OnClickListener接口并将自引用传递给Button,则onclick监听器将保留对该活动对象的引用,因此在其中保留整个活动对象会很重,因此使用具有OnClickListener类型的局部变量是更优化的方式。

因此,总体而言,创建具有OnClickListener类型的局部变量是处理任何类型的事件的最佳实践,而不仅仅是Button上的onClick事件。


1
谢谢你的回答,你说在按钮上保持整个活动对象会很重。难道它只能保持对活动对象的引用吗?看起来你的意思是它会再次加载Activity对象到内存中?只是为了澄清一下。 - Mateus Schneiders

0

还有另一种可能性

class MyListener implements onClickHandler{
    public MyListener(SomeType parameter)
    {
       m_parameter = parameter;
    }
    @Override
    public void onClick(View v) {
        // do some stuff based on the value of m_parameter
    }
    private SomeType m_parameter;
};

protected void onCreate(Bundle savedInstanceState) {
    ...
    findViewById(R.id.Button1).setOnClickListener(new MyListener(parameter1));
    findViewById(R.id.Button2).setOnClickListener(new MyListener(parameter2));
    ...
}

这样可以避免根据被点击的视图(按钮)来确定要执行的操作。显然,您可以在构造函数中使用多个参数,以支持指定更丰富的操作,而不需要将资源ID或按钮标识硬编码到MyListener对象中。


谢谢您的回答。我认为创建另一个实现Listener接口的类是一个相当有效的选项,但似乎更难让这个类意识到活动的上下文,以处理其他视图之类的事情。 - Mateus Schneiders

0

首先,每个人都应该习惯阅读匿名内部类。它们看起来很丑,但是它们被广泛使用,你会看到很多这样的代码。

话虽如此,我会选择第一种方式,因为它是本地化的 - 你可以看到你正在添加的监听器是针对你关心的按钮,在你添加它的位置。它允许监听多个按钮(而不是在类级别实现监听器)。

在风格上,我建议像这样实现只有一个方法的匿名内部类:

button.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        //do stuff
    }});

"

}});"

是一个很明显的瑕疵 - 这是有意为之的。它像旧时的"醒目标记"一样突出。这会吸引你的注意力,让你意识到特殊的事情正在发生 - 匿名内部类定义的结束。匿名内部类可能很难阅读 - 这种丑陋实际上有助于可读性。"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接