【问题标题】:Runtime equivalent to (XML) android:onClick?运行时相当于(XML)android:onClick?
【发布时间】:2014-02-25 15:18:46
【问题描述】:

从 1.6 开始,在 Android 中实现按钮处理程序的一种方法是将其放在声明按钮的 XML 中。 . .

...
android:onClick="TheButtonHandler"
...

然后将处理程序例程放在 Activity 类中。 . .

   public void TheButtonHandler(View target) {
    // ... button handler code
 }

我有一些 Android 代码,其中所有按钮都是在初始化期间在运行时用 Java 创建的,而不是在 XML 中,但我想做与上述 XML 相同的事情,包括指定按钮处理程序。 注意,我希望按钮处理程序位于它们自己的单独例程中,就像我在上面的示例中在 XML 中声明它们一样,我不希望按钮处理程序代码嵌入到我的初始化代码。

我见过使用 setOnClickListener 的示例,但处理程序代码始终是内嵌的,例如,

  demoButton.setOnClickListener(new Button.OnClickListener(){
  @Override
  public void onClick(View arg0) {
               // ... button handler code     
  }});

...这是我不想要的,因为这会将按钮处理程序代码放在初始化按钮的位置。 android:onClick 的 Java 运行时等效项是什么?

【问题讨论】:

  • 所有回合都会导致View.setOnClickListener()的使用...希望别无选择...
  • @GopalRao 你为什么希望它?
  • 谁投票决定关闭它,为什么?
  • @blackbelt 我没听懂你?对于View.setOnClickListener() 之外的动态创建的视图,android:onClick 是否有任何替代方案?
  • 不,只有这些。但为什么是“希望”? @GopalRao

标签: android


【解决方案1】:

相当于setOnClickListener()View.OnClickListener

如果您examine the platform source,您会看到使用onClick 属性定义的方法被转换为通过Java 反射调用命名方法的OnClickListener

我见过使用 setOnClickListener 的示例,但处理程序代码总是嵌入内联...这是我不想要的,因为这会将按钮处理程序代码放在按钮初始化的位置

您可以使用您的OnClickListeners,例如像这样的成员变量:

private OnClickListener mClickListener = new OnClickListener() { ... };

//

    view.setOnClickListener(mClickListener);

在不同的地方进行初始化和点击处理。

【讨论】:

  • 我相信你的话——我不会尝试阅读 19K 行的源代码——如果我们使用 XML,平台会免费提供很多魔法,但如果我们使用用java做。因此,如果我们在 java 中这样做,我们必须添加我们自己的复杂层 - 命名或匿名类、标签、case 语句或其他任何东西。所以我的问题的答案是“没有等价物”。
  • @user316117 实际上只有大约 40 行代码,因为他链接到了适当的 switch 案例。值得看看他们是如何做到这一点的。
【解决方案2】:

方法一

public class YourActivity extends Activity implements View.OnClickListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //....

        myButton1.setOnClickListener(this);
        myButton2.setOnClickListener(this);
        myButton3.setOnClickListener(this);
        myButton4.setOnClickListener(this);



        myButton1.setTag(0);
        myButton2.setTag(1);
        myButton3.setTag(2);
        myButton4.setTag(3);
    }

    @Override
    public void onClick(View v) {
        //Do your stuff
        switch ((int) v.getTag()) {

            case 0:
                //First button pressed;
                break;
            case 1:
                //Second button pressed;
                break;
            case 2:
                //Third button pressed;
                break;
            case 3:
                //Fourth button pressed;
                break;
            default:
                //Unknown value, handle an error
                break;
        }
    }
}

方法二

public class YourActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //....

        myButton1.setOnClickListener(new Button.OnClickListener(){
            @Override
            public void onClick(View arg0) {
               // ... button handler code     
            }
        });

        myButton2.setOnClickListener(new Button.OnClickListener(){
            @Override
            public void onClick(View arg0) {
               // ... button handler code     
            }
        });

        myButton3.setOnClickListener(new Button.OnClickListener(){
            @Override
            public void onClick(View arg0) {
               // ... button handler code     
            }
        });

        myButton4.setOnClickListener(new Button.OnClickListener(){
            @Override
            public void onClick(View arg0) {
               // ... button handler code     
            }
        });
    }
}

【讨论】:

  • 不确定我是否理解这一点。每个活动一个处理程序?在我的活动中,我有一个 2x3 的按钮网格(6 个按钮) 在 XML 中,我可以在同一个活动中声明 6 个处理程序。所以我不确定这在什么意义上是等价的。
  • 您可以内联您的OnClickListener,或者当您获得按钮时,您可以调用myButton.setTag((int) SomeId);,然后在onClick 中在标签上运行switch。我现在用一个例子更新我的帖子。
  • 好的,请参阅上面的代码以获取两种方法的示例,也没有什么可以阻止您内联您的onClick,然后只需在onClick 中调用MyHandlingFunction(); 以分离您的逻辑。这可能是我会采用的方法。
  • 感谢您为此付出的努力,因此我给了您 +1,但我认为您真的说的是真的 b> 不等同于我使用 XML 得到的。标记方法是一种解决方法,可以模拟在 XML 中执行此操作的某些方面,但会增加标记和案例代码的复杂性。
  • 是的,这是我能想到的最好的解决方法,但为了简单起见,我认为使用 android:onClick 是最好的。另请参阅 Iaalto 的回答,这也是您可以使用的另一种方法,它保留了对该方法的作用的可读引用(就像方法名称一样),但我不会说它等同于 XML。
【解决方案3】:

如果这是您的要求,您不必将它们内联。 您可以创建自己的类,例如:

MyButtonClickListener implements Button.OnClickListener
{
  ...
}

这可以在别处定义。然后您可以在初始化代码中类似地引用它,但不会占用太多空间以提高可读性。

demoButton.setOnClickListener(new MyButtonClickListener());

如果这确实是你的问题。

【讨论】:

  • 当然,但这仍然比 XML 中的 android:OnClick 更加混乱和复杂。所以我真的不会称它为等价的。 XML 中的大多数内容在 Java 中都有对应的内容。您可以在 java 和 XML 中的 1 行中设置颜色或文本或启用状态(等)。
  • 这会在一行中设置监听器。即使您在 XML 中设置方法,您仍然必须编写方法。
  • 但这为每个按钮处理程序实现了一个单独的类,对吧?在 XML 案例中,只有主 Activity 类和每个处理程序的单独例程。所以我看不出这是如何“等效”的。
【解决方案4】:

正如@laalto 已经指出的那样,Android View 本身只是采用处理程序的名称并使用 Java 反射来创建一个 OnClickListener 对象。我从 View.java 中挖掘出代码并将其包装在一个单独的对象中:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.app.Activity;
import android.view.View;

public class ViewOnClickHandler implements View.OnClickListener{

    Activity mActivity;
    Method mHandler;
    ViewOnClickHandler(Activity activity, View view, String handlerName){
        mActivity = activity;
        try {
            mHandler = activity.getClass().getMethod(handlerName, View.class);
        } catch (NoSuchMethodException e) {
            int id = view.getId();
            String idText = id == View.NO_ID ? "" : " with id '"
                    + mActivity.getResources().getResourceEntryName(id) + "'";
            throw new IllegalStateException("Could not find a method " +
                    handlerName + "(View) in the activity "
                    + activity.getClass() + " for onClick handler"
                    + " on view " + view.getClass() + idText, e);
        }           
    }
    @Override
    public void onClick(View v) {
        try {
            mHandler.invoke(mActivity, v);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Could not execute non "
                    + "public method of the activity", e);
        } catch (InvocationTargetException e) {
            throw new IllegalStateException("Could not execute "
                    + "method of the activity", e);
        }
    }

    static void set(Activity activity, View view, String handlerName){
        view.setOnClickListener(new ViewOnClickHandler(activity, view, handlerName));

    }
}

如果您将此代码放在您选择的包中并将该类导入您的活动中,则示例中的代码可以缩减为:

ViewOnClickHandler.set(this, demoButton, "TheButtonHandler");

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 2023-03-07
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 2017-04-11
    相关资源
    最近更新 更多