24

I have an edit text which functions as a search box in my application. In Jelly Bean on my Nexus 7 when I type something into the text box which I am listening on and hit enter the KeyEvent = null and ActionId = 0 passed into the onEditorAction() method. Has anyone else encountered this? I'm thinking it might be a bug.

In the second if statement below I get a null pointer because the actionId = 0 and 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();
     }
}
dcow
  • 7,765
  • 3
  • 45
  • 65
LowDev1
  • 1,108
  • 2
  • 10
  • 19
  • Please use the `android-edittext` tag instead of `edittext` :) – Alex Lockwood Jul 02 '12 at 21:03
  • 3
    `event` is definitely sometimes `null`, going back to at least Honeycomb. Here is a sample project showing how I use `onEditorAction()`: https://github.com/commonsguy/cw-omnibus/tree/master/ActionBar/ActionBarDemo – CommonsWare Jul 03 '12 at 13:35
  • @CommonsWare I tried your example: – William T. Mallard Jan 15 '14 at 19:10
  • As an example for my sing in this works for me: android:imeActionId="@integer/sing_in_action" android:imeActionLabel="@string/sign_in" – jpardogo Aug 18 '15 at 12:15
  • for **[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` may be **[EditorInfo.IME_NULL](http://developer.android.com/intl/es/reference/android/view/inputmethod/EditorInfo.html#IME_NULL)**, which means *the enter key being pressed*. – Alex Cohn Oct 28 '15 at 11:09

6 Answers6

43

Ended up adding in a null check for KeyEvent. Thanks to commonsware for pointing out this happens on 3.0+. Seems more like a workaround then a solution, but it works.

// 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();
    }
}
LowDev1
  • 1,108
  • 2
  • 10
  • 19
  • 7
    for **[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` may be **[EditorInfo.IME_NULL](http://developer.android.com/intl/es/reference/android/view/inputmethod/EditorInfo.html#IME_NULL)**, which means *the enter key being pressed*. – Alex Cohn Oct 28 '15 at 10:43
  • Awesome! Thanks. Out of multiple solutions on different questions, this one worked very well, even for Android M. – Shobhit Puri Nov 26 '15 at 03:31
  • 1
    Actually, EditorInfo.IME_ACTION_DONE is the Enter/Done key, t least on Android 4.4.2. – FractalBob Jul 15 '17 at 01:05
  • onEditorAction() invokes twice by action down and up! if event is null, how to check KeyEvent.ACTION_DOWN?? @LowDev1 – arunrk Feb 19 '18 at 13:27
  • @arunrk, I don't know how this can happen, but you can use time for calculating a difference between events firing. – CoolMind Mar 07 '19 at 09:33
7

I found that my "bug-like behavior" was due to imeActionLabel complicating things. I only used it because it was mentioned in the Text Fields Guide as a way to have a custom return key label. Here are the results of my tests in Lollipop,

Case 1: default, return key symbol = closing angle bracket

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

onEditorAction is called once.

  • KeyEvent = null, actionId = 5 = EditorInfo.IME_ACTION_NEXT
    • if return true, cursor remains in EditText, keyboard open
    • if return false, cursor moves to next focusable, keyboard open if necessary

Case 2: imeOptions, return key symbol = checkmark

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

onEditorAction is called once.

  • KeyEvent = null, actionId = 6 = EditorInfo.IME_ACTION_DONE
    • if return true, cursor remains in EditText, keyboard open
    • if return false, cursor remains in EditText, keyboard closes

Case 3: imeActionLabel, return key symbol = "URdone"

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

onEditorAction can be called more than once.

  • KeyEvent = null, actionId = 0

    • if return true, cursor remains in EditText, keyboard open, onEditorAction is NOT called a second time
    • if return false, onEditorAction is called a SECOND time:
  • KeyEvent = KeyEvent.ACTION_DOWN, actionId = 0

    • if return false, cursor moves to next focusable, keyboard open if necessary, onEditorAction is NOT called a third time
    • if return true, onEditorAction is called a THIRD time:
  • KeyEvent = KeyEvent.ACTION_UP, actionId = 0

    • if return true, cursor remains in EditText, keyboard open
    • if return false, cursor moves to next focusable, keyboard open if necessary

NOTES:

I'm not sure if actionId = 0 is from EditorInfo.IME_ACTION_UNSPECIFIED or EditorInfo.IME_NULL.

If the next focusable is non-editable, the return key symbol becomes a left pointing arrow.

You can also use setOnFocusChangeListener to override onFocusChange, which will be called according to the above cursor behavior.

Michelle Norris
  • 568
  • 7
  • 14
3

Beside KeyEvent.ACTION_UP we also need to capture KeyEvent.ACTION_DOWN. Unless KeyEvent.ACTION_UP will never be passed to EditText so our onEditorAction will not work. Example:

@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;
    }
}

You have to replace EditorInfo.IME_ACTION_DONE to correct version of EditorInfo.IME_ACTION_ according to android:imeOptions="actionNext"

Jacek Marchwicki
  • 1,565
  • 15
  • 17
2

It might be worth noting, that you can get more than one event for the click on Enter (depending on the android version). One for the KeyDown (KeyEvent.ACTION_DOWN), one for the KeyUp (KeyEvent.ACTION_UP). When I forgot to check that I accidentally started two server calls for the same action.

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;
}
});
koljaTM
  • 10,064
  • 2
  • 40
  • 42
  • I wonder which reason this has.For me this is really annoying. The enter button represents the enter event, and this surely is one of the oldest and most important keys on each computer-like device with human interface. So, is there a reason, why it seems to be lost since Android 3.0 ? As I encountered this problem, I would like to know, what is wrong with EditorInfo.IME_ACTION_DONE ? – icbytes Jan 28 '14 at 12:00
1

You dont discover the truth, if you customize return key. You need both set imeActionLabel and imeActionId in your layout. Such as:

imeActionLabel="xxxx"
imeActionId = "6"

In your java code:

@Override
public boolean onEditorAction(TextView v, int actionId,  KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
     doSomeThing();
     return true;
   }

    return false;
}

It will work fine.

MLavoie
  • 9,671
  • 41
  • 36
  • 56
David Dai
  • 21
  • 3
0

The action id is set to 0 by default for any enter event.

From the Android documentation:

actionId int: Identifier of the action. This will be either the identifier you supplied, or EditorInfo#IME_NULL if being called due to the enter key being pressed.

So the proper way to handle enter key events would be:

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