android EditText - finished typing event

AndroidAndroid Edittext

Android Problem Overview


I want to catch an event when the user finishes editing EditText.

How can it be done?

Android Solutions


Solution 1 - Android

Better way, you can also use EditText onFocusChange listener to check whether user has done editing: (Need not rely on user pressing the Done or Enter button on Soft keyboard)

 ((EditText)findViewById(R.id.youredittext)).setOnFocusChangeListener(new OnFocusChangeListener() {
    
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
       
      // When focus is lost check that the text field has valid values.
      
      if (!hasFocus) { {
         // Validate youredittext
      }
    }
 });

Note : For more than one EditText, you can also let your class implement View.OnFocusChangeListener then set the listeners to each of you EditText and validate them as below

((EditText)findViewById(R.id.edittext1)).setOnFocusChangeListener(this);
((EditText)findViewById(R.id.edittext2)).setOnFocusChangeListener(this);

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
       
      // When focus is lost check that the text field has valid values.

      if (!hasFocus) {
        switch (view.getId()) {
           case R.id.edittext1:
                 // Validate EditText1
                 break;
           case R.id.edittext2:
                 // Validate EditText2
                 break;
        }
      }
    }

Solution 2 - Android

When the user has finished editing, s/he will press Done or Enter

((EditText)findViewById(R.id.youredittext)).setOnEditorActionListener(
    new EditText.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_SEARCH ||
                    actionId == EditorInfo.IME_ACTION_DONE ||
                    event != null &&
                    event.getAction() == KeyEvent.ACTION_DOWN &&
                    event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                if (event == null || !event.isShiftPressed()) {
                   // the user is done typing. 

                   return true; // consume.
                }                
            }
            return false; // pass on to other listeners. 
        }
    }
);

Solution 3 - Android

I personally prefer automatic submit after end of typing. Here's how you can detect this event.

Declarations and initialization:

private Timer timer = new Timer();
private final long DELAY = 1000; // in ms

Listener in e.g. onCreate()

EditText editTextStop = (EditText) findViewById(R.id.editTextStopId);
	editTextStop.addTextChangedListener(new TextWatcher() {
        @Override
		public void beforeTextChanged(CharSequence s, int start, int count,
				int after) {
		}
        @Override
		public void onTextChanged(final CharSequence s, int start, int before,
				int count) {
			if(timer != null)
				timer.cancel();
		}
		@Override
		public void afterTextChanged(final Editable s) {
            //avoid triggering event when text is too short
			if (s.length() >= 3) {				
									
				timer = new Timer();
				timer.schedule(new TimerTask() {
					@Override
					public void run() {
						// TODO: do what you need here (refresh list)
						// you will probably need to use
						// runOnUiThread(Runnable action) for some specific
						// actions
						serviceConnector.getStopPoints(s.toString());
					}

				}, DELAY);
			}
		}
	});

So, when text is changed the timer is starting to wait for any next changes to happen. When they occure timer is cancelled and then started once again.

Solution 4 - Android

You can do it using setOnKeyListener or using a textWatcher like:

Set text watcher editText.addTextChangedListener(textWatcher);

then call

private TextWatcher textWatcher = new TextWatcher() {

		@Override
		public void onTextChanged(CharSequence s, int start, int before, int count) {
			//after text changed
		}

		@Override
		public void beforeTextChanged(CharSequence s, int start, int count,
				int after) {
		}

		@Override
		public void afterTextChanged(Editable s) {

		}
	};

Solution 5 - Android

I solved this problem this way. I used kotlin.

        var timer = Timer()
        var DELAY:Long = 2000

        editText.addTextChangedListener(object : TextWatcher {

            override fun afterTextChanged(s: Editable?) {
                Log.e("TAG","timer start")
                timer = Timer()
                timer.schedule(object : TimerTask() {
                    override fun run() {
                        //do something
                    }
                }, DELAY)
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                Log.e("TAG","timer cancel ")
                timer.cancel() //Terminates this timer,discarding any currently scheduled tasks.
                timer.purge() //Removes all cancelled tasks from this timer's task queue.
            }
        })

Solution 6 - Android

both @Reno and @Vinayak B answers together if you want to hide the keyboard after the action

textView.setOnEditorActionListener(new EditText.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(textView.getWindowToken(), 0);
            return true;
        }
        return false;
    }
});

textView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
             // your action here
        }
    }
});

Solution 7 - Android

Although many answers do point in the right direction I think none of them answers what the author of the question was thinking about. Or at least I understood the question differently because I was looking for answer to similar problem. The problem is "How to know when the user stops typing without him pressing a button" and trigger some action (for example auto-complete). If you want to do this start the Timer in onTextChanged with a delay that you would consider user stopped typing (for example 500-700ms), for each new letter when you start the timer cancel the earlier one (or at least use some sort of flag that when they tick they don't do anything). Here is similar code to what I have used:

new Timer().schedule(new TimerTask() {
  @Override
  public void run() {
     if (!running) {							
        new DoPost().execute(s.toString());
  });
 }
}, 700);

Note that I modify running boolean flag inside my async task (Task gets the json from the server for auto-complete).

Also keep in mind that this creates many timer tasks (I think they are scheduled on the same Thread thou but would have to check this), so there are probably many places to improve but this approach also works and the bottom line is that you should use a Timer since there is no "User stopped typing event"

Solution 8 - Android

A different approach ... here is an example: If the user has a delay of 600-1000ms when is typing you may consider he's stopped.

 myEditText.addTextChangedListener(new TextWatcher() {
             
            private String s;
            private long after;
			private Thread t;
            private Runnable runnable_EditTextWatcher = new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        if ((System.currentTimeMillis() - after) > 600)
                        {
                            Log.d("Debug_EditTEXT_watcher", "(System.currentTimeMillis()-after)>600 ->  " + (System.currentTimeMillis() - after) + " > " + s);
                            // Do your stuff
                            t = null;
                            break;
                        }
                    }
                }
            };
            
            @Override
            public void onTextChanged(CharSequence ss, int start, int before, int count) {
                s = ss.toString();
            }
            
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            
            @Override
            public void afterTextChanged(Editable ss) {
                after = System.currentTimeMillis();
                if (t == null)
                {
                    t = new Thread(runnable_EditTextWatcher);
                      t.start();
                }
            }
        });

Solution 9 - Android

Okay this will work 100% for sure.

First you will need to setup listener if keyboard is show or hide. If keyboard is showing then probably user is typing, otherwise done typing.

final View activityRootView = findViewById(android.R.id.content);
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                    Rect r = new Rect();
                    //r will be populated with the coordinates of your view that area still visible.
                    activityRootView.getWindowVisibleDisplayFrame(r);

                    int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
                    if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...

                        isTyping = true;
                    } else {
//to make sure this will call only once when keyboard is hide.
                        if(isTyping){
                            isTyping = false;
                        }
                    }
            }
        });

Solution 10 - Android

I had the same issue and did not want to rely on the user pressing Done or Enter.

My first attempt was to use the onFocusChange listener, but it occurred that my EditText got the focus by default. When user pressed some other view, the onFocusChange was triggered without the user ever having assigned it the focus.

Next solution did it for me, where the onFocusChange is attached if the user touched the EditText:

final myEditText = new EditText(myContext); //make final to refer in onTouch
myEditText.setOnTouchListener(new OnTouchListener() {
		
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			myEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
				
				@Override
				public void onFocusChange(View v, boolean hasFocus) {
					if(!hasFocus){
                        // user is done editing
                    }
                }
            }
        }
}

In my case, when the user was done editing the screen was rerendered, thereby renewing the myEditText object. If the same object is kept, you should probably remove the onFocusChange listener in onFocusChange to prevent the onFocusChange issue described at the start of this post.

Solution 11 - Android

I had the same problem when trying to implement 'now typing' on chat app. try to extend EditText as follows:

public class TypingEditText extends EditText implements TextWatcher {

private static final int TypingInterval = 2000;


public interface OnTypingChanged {
	public void onTyping(EditText view, boolean isTyping);
}
private OnTypingChanged t;
private Handler handler;
{
	handler = new Handler();
}
public TypingEditText(Context context, AttributeSet attrs, int defStyleAttr) {
	super(context, attrs, defStyleAttr);
	this.addTextChangedListener(this);
}

public TypingEditText(Context context, AttributeSet attrs) {
	super(context, attrs);
	this.addTextChangedListener(this);
}

public TypingEditText(Context context) {
	super(context);
	this.addTextChangedListener(this);
}

public void setOnTypingChanged(OnTypingChanged t) {
	this.t = t;
}

@Override
public void afterTextChanged(Editable s) {
	if(t != null){
		t.onTyping(this, true);
		handler.removeCallbacks(notifier);
		handler.postDelayed(notifier, TypingInterval);
	}
	
}

private Runnable notifier = new Runnable() {
	
	@Override
	public void run() {
		if(t != null)
			t.onTyping(TypingEditText.this, false);
	}
};

@Override
public void beforeTextChanged(CharSequence s, int start, int count,	int after) { }
	

@Override
public void onTextChanged(CharSequence text, int start,	int lengthBefore, int lengthAfter) { }

}

Solution 12 - Android

I ended her with the same problem and I could not use the the solution with onEditorAction or onFocusChange and did not want to try the timer. A timer is too dangerous for may taste, because of all the threads and too unpredictable, as you do not know when you code is executed.

The onEditorAction do not catch when the user leave without using a button and if you use it please notice that KeyEvent can be null. The focus is unreliable at both ends the user can get focus and leave without enter any text or selecting the field and the user do not need to leave the last EditText field.

My solution use onFocusChange and a flag set when the user starts editing text and a function to get the text from the last focused view, which I call when need.

I just clear the focus on all my text fields to tricker the leave text view code, The clearFocus code is only executed if the field has focus. I call the function in onSaveInstanceState so I do not have to save the flag (mEditing) as a state of the EditText view and when important buttons is clicked and when the activity is closed.

Be careful with TexWatcher as it is call often I use the condition on focus to not react when the onRestoreInstanceState code entering text. I

final EditText mEditTextView = (EditText) getView();

    mEditTextView.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (!mEditing && mEditTextView.hasFocus()) {
                mEditing = true;
            }
        }
    });
    mEditTextView.setOnFocusChangeListener(new View.OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus && mEditing) {
                mEditing = false;
                ///Do the thing
            }
        }
    });
protected void saveLastOpenField(){
    for (EditText view:getFields()){
            view.clearFocus();
    }
}

Solution 13 - Android

I have done something like this abstract class that can be used in place of TextView.OnEditorActionListener type.

abstract class OnTextEndEditingListener : TextView.OnEditorActionListener {

    override fun onEditorAction(textView: TextView?, actionId: Int, event: KeyEvent?): Boolean {

        if(actionId == EditorInfo.IME_ACTION_SEARCH ||
                actionId == EditorInfo.IME_ACTION_DONE ||
                actionId == EditorInfo.IME_ACTION_NEXT ||
                event != null &&
                event.action == KeyEvent.ACTION_DOWN &&
                event.keyCode == KeyEvent.KEYCODE_ENTER) {

            if(event == null || !event.isShiftPressed) {
                // the user is done typing.
                return onTextEndEditing(textView, actionId, event)
            }
        }
        return false // pass on to other listeners
    }

    abstract fun onTextEndEditing(textView: TextView?, actionId: Int, event: KeyEvent?) : Boolean
}

Solution 14 - Android

Simple to trigger finish typing in EditText

worked for me , if you using java convert it

In Kotlin

youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
    Handler().postDelayed({
        if (currentTextLength == searchTerm?.length) {
            // your code 
           Log.d("aftertextchange", "ON FINISH TRIGGER")
          }
       }, 3000)
}

Solution 15 - Android

Use this class

DelayedTextWatcher.java

import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
public class DelayedTextWatcher implements TextWatcher {

    private String text;
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            listener.onTimeout(text);
        }
    };

    public static interface DelayedTextWatcherListener {
        public void onTimeout(CharSequence text);
    }

    private long DELAY = 200;
    private Handler handler = new Handler();
    private DelayedTextWatcherListener listener;

    public DelayedTextWatcher(DelayedTextWatcherListener l) {
        listener = l;
    }

    @Override
    public void afterTextChanged(Editable s) {
        text = s.toString();
        handler.postDelayed(runnable, DELAY);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        handler.removeCallbacks(runnable);
    }

}

Solution 16 - Android

You can use Handler for delay. This issue occures due to multiple call for filter and a count to stop multiple call of handler.

final int[] Count = {0};
                etSearch.addTextChangedListener(new TextWatcher() {
                    @Override
                    public void beforeTextChanged(final CharSequence s, int start, int count,
                                                  int after) {
                        if (Count[0] == 0) {
                            Count[0]++;
                            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                //apply filter call here
                                    Count[0] = 0;
                                }
                            }, 1000);
                        }
                    }

                    @Override
                    public void onTextChanged(final CharSequence s, int start, int before,
                                              int count) {
                    }

                    @Override
                    public void afterTextChanged(final Editable s) {

                    }
                });

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioneddyukView Question on Stackoverflow
Solution 1 - AndroidVinayak BevinakattiView Answer on Stackoverflow
Solution 2 - AndroidRenoView Answer on Stackoverflow
Solution 3 - AndroidZimaXXXView Answer on Stackoverflow
Solution 4 - AndroidShineDownView Answer on Stackoverflow
Solution 5 - AndroidFahed HermozaView Answer on Stackoverflow
Solution 6 - AndroidTyler DavisView Answer on Stackoverflow
Solution 7 - AndroidIgor ČordašView Answer on Stackoverflow
Solution 8 - AndroidCristi MarisView Answer on Stackoverflow
Solution 9 - AndroidKritView Answer on Stackoverflow
Solution 10 - AndroidJosView Answer on Stackoverflow
Solution 11 - AndroidNadavView Answer on Stackoverflow
Solution 12 - AndroidRezderView Answer on Stackoverflow
Solution 13 - AndroidMichał ZiobroView Answer on Stackoverflow
Solution 14 - AndroidKharis AzharView Answer on Stackoverflow
Solution 15 - AndroidOmkar TView Answer on Stackoverflow
Solution 16 - Androidahmad bajwaView Answer on Stackoverflow