在onEditorAction()中出现null keyevent和actionid = 0的错误(Jelly Bean / Nexus 7)

24

我的应用中有一个作为搜索框的编辑文本。在我的Nexus 7上的Jelly Bean版本中,当我在文本框中输入一些文字并按下回车键时,传递到onEditorAction()方法的KeyEvent = null和ActionId = 0。有其他人遇到过这个问题吗?我想这可能是一个错误。

在下面的第二个if语句中,由于actionId = 0和KeyEvent = null,我得到了一个空指针异常。

// Search field logic.
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    Log.d(TAG, "onEditorAction");
    if (event != null && event.getAction() != KeyEvent.ACTION_DOWN)
        return false;
    if (actionId == EditorInfo.IME_ACTION_SEARCH
            || event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
              .....Do some stuff();
     }
}

请使用 android-edittext 标签代替 edittext :) - Alex Lockwood
3
“event”有时候肯定是“null”,至少从Honeycomb开始就是这样。这里有一个示例项目,展示了我如何使用“onEditorAction()”:https://github.com/commonsguy/cw-omnibus/tree/master/ActionBar/ActionBarDemo - CommonsWare
@CommonsWare 我尝试了你的例子: - William T. Mallard
作为我的登录示例,以下代码适用于我:android:imeActionId="@integer/sing_in_action" android:imeActionLabel="@string/sign_in"。 - jpardogo
对于[onEditorAction(TextView v, int actionId, KeyEvent event)](http://developer.android.com/intl/es/reference/android/widget/TextView.OnEditorActionListener.html#onEditorAction(android.widget.TextView,%20int,%20android.view.KeyEvent))actionId可能是[EditorInfo.IME_NULL](http://developer.android.com/intl/es/reference/android/view/inputmethod/EditorInfo.html#IME_NULL),这意味着按下回车键 - Alex Cohn
6个回答

43

最后我加上了一个KeyEvent的空值检查。感谢commonsware指出这在3.0+版本上会发生。虽然更像是一种解决方法而非解决方案,但它能够起作用。

// Search field logic.
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    Log.d(TAG, "onEditorAction");
    if (event != null && event.getAction() != KeyEvent.ACTION_DOWN) {
        return false;
    } else if (actionId == EditorInfo.IME_ACTION_SEARCH
        || event == null
        || event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
              .....Do some stuff();
    }
}

7
对于onEditorAction(TextView v, int actionId, KeyEvent event)actionId可能是EditorInfo.IME_NULL,表示按下Enter键 - Alex Cohn
太棒了!谢谢。在不同问题的多个解决方案中,这个非常有效,甚至适用于Android M。 - Shobhit Puri
1
实际上,EditorInfo.IME_ACTION_DONE 是“完成/确定”键,至少在 Android 4.4.2 上是这样。 - FractalBob
onEditorAction() 会被按下和松开两次调用!如果事件为空,如何检查 KeyEvent.ACTION_DOWN?@LowDev1 - arunrk
@arunrk,我不知道这是怎么发生的,但你可以使用时间来计算事件触发之间的差异。 - CoolMind

7
我发现我的“bug-like行为”是由于imeActionLabel让事情变得更加复杂。我之前使用它仅仅是因为在文本字段指南中提到了它可以用来自定义返回键标签。这是我在Lollipop中测试的结果: 案例1:默认情况下,返回键符号=闭合角括号
<EditText
    android:singleLine="true"
    android:inputType="textUri"/>

onEditorAction只会被调用一次。

  • KeyEvent = null,actionId = 5 = EditorInfo.IME_ACTION_NEXT
    • 如果返回true,光标保持在EditText中,键盘打开
    • 如果返回false,光标移动到下一个可获得焦点的位置,必要时键盘打开

情况2:imeOptions,返回键符号=勾号

<EditText
    android:singleLine="true"
    android:inputType="textUri"
    android:imeOptions="actionDone"/>

onEditorAction只会被调用一次。

  • KeyEvent = null, actionId = 6 = EditorInfo.IME_ACTION_DONE
    • 如果返回true,则光标保留在EditText中,键盘打开
    • 如果返回false,则光标保留在EditText中,键盘关闭

情况3:imeActionLabel,返回键符号为"URdone"

<EditText
    android:singleLine="true"
    android:inputType="textUri"
    android:imeOptions="actionDone"
    android:imeActionLabel="URdone"/>

onEditorAction可能会被调用多次。

  • KeyEvent = null,actionId = 0

    • 如果返回true,则光标仍停留在EditText中,键盘打开,onEditorAction不会第二次被调用
    • 如果返回false,则onEditorAction将被调用第二次:
  • KeyEvent = KeyEvent.ACTION_DOWN,actionId = 0

    • 如果返回false,则光标移动到下一个可聚焦的位置,必要时键盘打开,onEditorAction不会第三次被调用
    • 如果返回true,则onEditorAction将被调用第三次:
  • KeyEvent = KeyEvent.ACTION_UP,actionId = 0

    • 如果返回true,则光标仍停留在EditText中,键盘打开
    • 如果返回false,则光标移动到下一个可聚焦的位置,必要时键盘打开

注:

我不确定actionId = 0是来自EditorInfo.IME_ACTION_UNSPECIFIED还是EditorInfo.IME_NULL

如果下一个可聚焦的位置是不可编辑的,则返回键符号变为向左指向的箭头。

您还可以使用setOnFocusChangeListener来覆盖onFocusChange,根据上述光标行为调用。


3
除了捕获 KeyEvent.ACTION_UP 外,我们还需要捕获 KeyEvent.ACTION_DOWN。如果不捕获 KeyEvent.ACTION_UP,它将永远不会传递到 EditText,因此我们的 onEditorAction 将无法工作。 示例:
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    final boolean isEnterEvent = event != null
            && event.getKeyCode() == KeyEvent.KEYCODE_ENTER;
    final boolean isEnterUpEvent = isEnterEvent && event.getAction() == KeyEvent.ACTION_UP;
    final boolean isEnterDownEvent = isEnterEvent && event.getAction() == KeyEvent.ACTION_DOWN;

    if (actionId == EditorInfo.IME_ACTION_DONE || isEnterUpEvent ) {
        // Do your action here
        performLogin();
        return true;
    } else if (isEnterDownEvent) {
        // Capture this event to receive ACTION_UP
        return true;
    } else {
        // We do not care on other actions
        return false;
    }
}

根据android:imeOptions="actionNext",您需要将EditorInfo.IME_ACTION_DONE替换为正确版本的EditorInfo.IME_ACTION_


2

值得注意的是,对于点击“Enter”键,您可能会收到多个事件(取决于Android版本)。其中一个是KeyDown事件(KeyEvent.ACTION_DOWN),另一个是KeyUp事件(KeyEvent.ACTION_UP)。当我忘记检查时,同一操作会意外启动两个服务器调用。

searchBox.setOnEditorActionListener(new OnEditorActionListener() {
// enter key in search box triggers search
@Override
public boolean onEditorAction(TextView v, int actionId,
        KeyEvent event) {
    if ((event != null && event.getAction() == KeyEvent.ACTION_UP) || event==null) {
        onSearchButtonClicked();
    }
    return true;
}
});

我想知道这是什么原因。对我来说,这真的很烦人。回车键代表回车事件,而且这肯定是每个计算机样式的设备与人类接口上最古老和最重要的键之一。那么,为什么似乎自从 Android 3.0 以来就失去了呢?当我遇到这个问题时,我想知道 EditorInfo.IME_ACTION_DONE 出了什么问题? - icbytes

1
如果您自定义返回键,则无法发现真相。 您需要在布局中同时设置 imeActionLabelimeActionId。例如:
imeActionLabel="xxxx"
imeActionId = "6"

在你的Java代码中:
@Override
public boolean onEditorAction(TextView v, int actionId,  KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
     doSomeThing();
     return true;
   }

    return false;
}

它将正常工作。


0

任何输入事件的默认操作ID都设置为0。

来自Android文档

actionId int:操作的标识符。这将是您提供的标识符,或者如果由于按下回车键而被调用,则为EditorInfo#IME_NULL。

因此,处理回车键事件的正确方法是:

@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    if (actionId == EditorInfo.IME_NULL) {
        // Handle return key here
        return true;
    }
    return false;
}

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