android editText: detect when user stops editing - android

I have an editText which represent an input for a search criteria. I want to know if there is a way to detect when user stops editing this editText so I can query the db for data for my list. For example, if the user types "test" I want to be notified only after user has typed the word, not after user types each letter, like text watcher does. Do you have any ideas? I would avoid to use some timer to measure milliseconds elapsed between key pres events.

Not incredibly elegant, but this should work.
Initializations:
long idle_min = 4000; // 4 seconds after user stops typing
long last_text_edit = 0;
Handler h = new Handler();
boolean already_queried = false;
Set up your runnable that will be called from the text watcher:
private Runnable input_finish_checker = new Runnable() {
public void run() {
if (System.currentTimeMillis() > (last_text_edit + idle_min - 500)) {
// user hasn't changed the EditText for longer than
// the min delay (with half second buffer window)
if (!already_queried) { // don't do this stuff twice.
already_queried = true;
do_stuff(); // your queries
}
}
}
};
Put this in your text watcher:
last_text_edit = System.currentTimeMillis();
h.postDelayed(input_finish_checker, idle_min);

First create the following field :
private Date _lastTypeTime = null;
Then make sure your your editText implements 'TextWatcher':
_editText.addTextChangedListener(this);
then, override the interface`s methods as follows:
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
{
_lastTypeTime = new Date();
}
#Override
public void afterTextChanged(Editable arg0)
{
}
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
{
// dispatch after done typing (1 sec after)
Timer t = new Timer();
TimerTask tt = new TimerTask()
{
#Override
public void run()
{
Date myRunTime = new Date();
if ((_lastTypeTime.getTime() + 1000) <= myRunTime.getTime())
{
post(new Runnable()
{
#Override
public void run()
{
Log.d("<tag>", "typing finished!!!");
}
});
}
else
{
Log.d("<tag>", "Canceled");
}
}
};
t.schedule(tt, 1000);
}

Here's how you can detect event you are looking for.
Declarations and initialization:
private Timer timer = new Timer();
private final long DELAY = 1000; // in ms
Listener in e.g. onCreate()
EditText editText = (EditText) findViewById(R.id.editTextStopId);
editText.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
queryDB();
}
}, 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.

This is how I did and works for me!
long delay = 1000; // 1 seconds after user stops typing
long last_text_edit = 0;
Handler handler = new Handler();
private Runnable input_finish_checker = new Runnable() {
public void run() {
if (System.currentTimeMillis() > (last_text_edit + delay - 500)) {
// TODO: do what you need here
DoStaff();
}
}
};
EditText editText = (EditText) findViewById(R.id.editTextStopId);
editText.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) {
//You need to remove this to run only once
handler.removeCallbacks(input_finish_checker);
}
#Override
public void afterTextChanged(final Editable s) {
//avoid triggering event when text is empty
if (s.length() > 0) {
last_text_edit = System.currentTimeMillis();
handler.postDelayed(input_finish_checker, delay);
} else {
}
}
});

the easiest way to check if editText is has text or NOT (only once) , do this :
private boolean newState;
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.somLayout);
edt.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if (!editable.trim().isEmpty()) {
checkIsTyping(true);
} else {
checkIsTyping(false);
}
}
});
}
private void checkIsTyping(boolean typeState) {
if (newState != typeState) {
Toast.makeText(appCompatActivity, "typingState " + newState,
Toast.LENGTH_SHORT).show();
}
newState = typeState;
}

Related

How to understand stop and start typing like whatsapp for EditText?

I have edittext and I want to understand stop and start typing. I listened textwatcher onTextChanged and I use timer for typing.
But when edittext's text is not empty, I don't understand correctly actual typing operation.
I want to see:
My edittext text:
--ad-- --> typing...
--ads-- --> typing...
--ads-- --> after 900 ms stop typing . ::: but not understand
TextWatcher textWatcher = new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, final int before, final int count) {
if (count != 0 && count >= before) {
typingTimer.startTyping();
return;
}
typingTimer.stopTyping();
}
};
You need a timer in fact.
TextWatcher textWatcher = new TextWatcher() {
private Timer timer = new Timer();
private final long TYPING_DELAY = 900; // milliseconds
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, final int before, final int count) {
// do what you want
// show "is typing"
timer.cancel();
timer = new Timer();
timer.schedule(
new TimerTask() {
#Override
public void run() {
// here, you're not typing anymore
}
},
TYPING_DELAY
);
}
};

I have to run a function just once when after user stops typing but my function runs multiple times

I have to run a function just once when after the user stops typing but my function runs multiple times.I have detected when a user stops typing but can't execute my function just once.
#Override
public void onTextChanged(CharSequence charSequence, final int i, final
int i1, final int i2) {
Timer timer = new Timer();
//Run after user stops typing
TimerTask tt = new TimerTask() {
#Override
public void run() {
Date myRunTime = new Date();
if ((lastTypeTime.getTime() + 1000) <= myRunTime.getTime()) {
Handler h = new Handler(Looper.getMainLooper());
h.post(new Runnable() {
#Override
public void run() {
Log.i("t_type", "Type Finish");
//Issue : This is printed multiple time.
}
});
} else {
Log.i("t_cancel", "cancel");//cancel
}
}
};
timer.schedule(tt, 2000);//two second delay after user stops typing
}
I solve the issue in this way. thanks #jitesh mohite
#Override
public void afterTextChanged(Editable editable) {
Log.i("t_text", editable.toString());
if (!isTyping) {
isTyping = true;
Log.i("t_type", "Typing");
}
timer.cancel();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
android.os.Handler handler = new
android.os.Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Log.i("t_type", "Type Finish");
Toast.makeText(SearchActivity.this, "Type Finish",
Toast.LENGTH_LONG).show();
isTyping = false;
}
});
}
}, 2000);
}
This is how I did and works for me!
long delay = 1000; // 1 seconds after user stops typing
long last_text_edit = 0;
Handler handler = new Handler();
private Runnable input_finish_checker = new Runnable() {
public void run() {
if (System.currentTimeMillis() > (last_text_edit + delay - 500)) {
// TODO: do what you need here
// ............
// ............
DoStaff();
}
}
};
EditText editText = (EditText) findViewById(R.id.editTextStopId);
editText.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){
//You need to remove this to run only once
handler.removeCallbacks(input_finish_checker);
}
#Override
public void afterTextChanged ( final Editable s){
//avoid triggering event when text is empty
if (s.length() > 0) {
last_text_edit = System.currentTimeMillis();
handler.postDelayed(input_finish_checker, delay);
} else {
}
}
}
);

Android AutoCompleteTextView : Perform a AsyncTask call only once on TextChange

I have an AutoCompleteTextView in my layout. After the user entered the first character, I'd like to do an API call, which I'm doing in an AsyncTask. I've used addTextChangedListener and I'm doing the API call on TextChanged. But the problem is that the API call is getting done each time the user makes any change to the AutoCompleteTextView.
But I'd want the API call to happen only once, that is after the first character is inputted. How do I achieve this ?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_places_search);
search_airport = (AutoCompleteTextView) findViewById(R.id.place_search);
autocompleteadapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, airports);
search_airport.setAdapter(autocompleteadapter);
search_airport.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) {
mAirport = new AsyncTaskAirport(search_airport.getEditableText().toString().substring(0, 1));
mAirport.execute((Void) null);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
try this,
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(s.toString().trim().length()==1){
mAirport = new AsyncTaskAirport(search_airport.getEditableText().toString().substring(0, 1));
mAirport.execute((Void) null);
}
}
You can solve your problem with a timer.Here is how
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
int COMPLETION_DELAY = 2000;
if (timer != null)
{
timer.cancel();
timer.purge();
timer = null;
}
timer = new Timer();
timer.schedule(new TimerTask()
{
#Override
public void run()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
#Override
public void run()
{
if (s.toString().length() >= appCompatAutoCompleteTextView.getThreshold())
{
//CALL WebService Here
}
}
});
}
}, COMPLETION_DELAY);
}
now your service will not be called when user making changes while typing in auto complete. service will only be called once user stops + 2 Second.

How to handle if user stopped after typing in edittext android?

I am developing an app for chat. I can get event to update typing status when user typed or when user erased fully, I can update as "not typing status" and showing as online. Till this process works fine.
But problem is when user typed some lines and stopped, I should not show typing which is applied in whatsapp. How to handle this?
Here is code what i done is.
ChatMsg.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (edtChatMsg.getText().toString().trim().length() > 0) {
if (!isTyping) {
isTyping = true;
serviceCall();
}
else{
isTyping = false;
serviceCall();
}
}
so at result
#Override
protected void onTyping(String message) {
if (message.equalsIgnoreCase("Typing…")) {
txtUserPersonStatus.setText("Typing…");
} else {
txtUserPersonStatus.setText("Online");
}
}
My question is how to handle when user typed in keyboard for a while and then stop.
Thanks.
Basically you need to implement some sort of timeout. Every time the user types something, you have to schedule a timeout and reset any timeouts you have scheduled before. Thus when the user stops typing the timer gets triggered after the specified time.
You can do this with a Handler for example:
final int TYPING_TIMEOUT = 5000; // 5 seconds timeout
final Handler timeoutHandler = new Handler();
final Runnable typingTimeout = new Runnable() {
public void run() {
isTyping = false;
serviceCall();
}
};
ChatMsg.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// reset the timeout
timeoutHandler.removeCallbacks(typingTimeout);
if (edtChatMsg.getText().toString().trim().length() > 0) {
// schedule the timeout
timeoutHandler.postDelayed(typingTimeout, TYPING_TIMEOUT);
if (!isTyping) {
isTyping = true;
serviceCall();
}
}
else {
isTyping = false;
serviceCall();
}
}
});
Use a Handler :
_AFKHandler = new Handler();
_AFKRunnable = new Runnable() {
public void run() {
isTyping = false;
serviceCall();
}
};
ChatMsg.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
_AFKHandler.removeCallbacks(_AFKRunnable);
if (edtChatMsg.getText().toString().trim().length() > 0) {
if (!isTyping) {
isTyping = true;
serviceCall();
_AFKHandler.postDelayed(_AFKRunnable,AFK_TIMEOUT_VALUE_IN_MS);
}
else{
isTyping = false;
serviceCall();
}
}
so at result
#Override
protected void onTyping(String message) {
if (message.equalsIgnoreCase("Typing…")) {
txtUserPersonStatus.setText("Typing…");
} else {
txtUserPersonStatus.setText("Online");
}
}
I think that you need use:
#Override
public void afterTextChanged(Editable arg0) {
// arg0=null ,Handler ---is empty ;
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// Handler --- is typing
}
Use this style , use coundown timer for 500ms. In my view this is the simplest way to solve this problem.Try it an let me know you sugessions
lateinit var textFinishTimer: CountDownTimer
EditText.doAfterTextChanged {
if (this::textFinishTimer.isInitialized) {
textFinishTimer.cancel()
}
textFinishTimer =
object : CountDownTimer(500, 100) {
override fun onTick(p0: Long) {}
override fun onFinish() {
if (oldKeyword == it.toString()) {
return
}else{
//Your logic comes here
}
}
}
.start()
}

Managing Delays in an android app

Hey guys, i would like to know how to manage delays in an android application, for example, I have an overridden method onTextChanged(). In relation to that I want to set a delay like .5 seconds in order to finalized what the user is typing in my autocomplete textbox. If the user hangs/stop typing in .5 sec, i wanted a certain method or implementation to execute in my code(i.e. my own filtering scheme/logic in my autocomplete textbox, just to lessen resource usage within my app, thanks).
Here's my sample code:
protected AutoCompleteTextView autoCompleteView;
protected AutoCompleteAdapter suggsAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
countries = getResources().getStringArray(R.array.countries_array);
autoCompleteView = (AutoCompleteTextView) findViewById(R.id.autocomplete_country);
TextWatcher textChecker = new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//here inside this overridden method, I wanted to create a delay in order to lessen the
//use of resources.
String enteredText = autoCompleteView.getText().toString();
refreshList(enteredText);
}
};
autoCompleteView.addTextChangedListener(textChecker);
}
and for example, the user typed "Lond"(for String like "London") with each letter typed less than .5 sec, I want all the previous onTextChanged() method called(method call in typing "L", "o" and "n") to be disregarded and only the onTextChanged() when the last letter was typed would be granted for execution.
How would I do that, please help me:(.
You can create a Handler subclass and call Handler.sendEmptyMessageDelayed() or Handler.sendMessageDelayed() method when onTextChanged() is triggered. And you can remove messages from the message queue using Handler.removeMessages(). You should process messages in Handler.handleMessage() method. So your onTextChanged() method will be something like:
mHandler.removeMessages(MESSAGE_TEXT_CHANGED);
mHandler.sendEmptyMessage(MESSAGE_TEXT_CHANGED, 500);
EDIT: Here's an example of code. I haven't tested it yet, so I'm not sure it works.
private static final int AUTOCOMPLETE_DELAY = 500;
private static final int MESSAGE_TEXT_CHANGED = 0;
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_TEXT_CHANGED) {
String enteredText = (String)msg.obj;
refreshList(enteredText);
}
}
};
// ... your code here
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String enteredText = autoCompleteView.getText().toString();
mHandler.removeMessages(MESSAGE_TEXT_CHANGED);
final Message msg = Message.obtain(mHandler, MESSAGE_TEXT_CHANGED, enteredText);
mHandler.sendMessageDelayed(msg, AUTOCOMPLETE_DELAY);
}
I am writing Running code for autocomplete.
First onTextChanged will be called.
public void onTextChanged(CharSequence s, int start, int before, int count) {
String newText = s.toString();
if(!newText.trim().equals(""))
Autocompletes_Timer(newText);
}
now we need a Handler.
Hander handler = new Handler();
private void Autocompletes_Timer(final String newText) {
// new text will be here. so if you type fast within 1 sec.
// handler will be remover each time so that handler post delay also be remove.
if(handler!= null)
handler.removeCallbacksAndMessages(null);
// new text will be in runnable with 1 sec delay.
handler.postDelayed(runnable(newText), 1000);
}
// it will be start work after 1 sec.
// if you stop the typing then it will complete work like as sending data at server.
// if you continue typing , it will not complete work and each type will be removeCallbackAndMessage.
private Runnable runnable(final String newText) {
Runnable runnable = new Runnable() {
#Override
public void run() {
Log.d("Autocompleted", newText);
// call AysncTask here
}
};
return runnable;
}
just copy and paste my code. It should be fix your problem . Enjoy.
use a CountDownTimer
protected AutoCompleteTextView autoCompleteView;
protected AutoCompleteAdapter suggsAdapter;
String TAG = "Timer";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
countries = getResources().getStringArray(R.array.countries_array);
autoCompleteView = (AutoCompleteTextView) findViewById(R.id.autocomplete_country);
TextWatcher textChecker = new TextWatcher() {
CountDownTimer countDownTimer = new CountDownTimer(500,100) {
#Override
public void onTick(long millisUntilFinished) {
Log.d(TAG, "addressTextWatcher.countDownTimer.onTick() -> Tick: " + millisUntilFinished);
}
#Override
public void onFinish() {
Log.d(TAG, "addressTextWatcher.countDownTimer.onTick() -> Finish");
String enteredText = autoCompleteView.getText().toString();
refreshList(enteredText);
}
};
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
countDownTimer.cancel();
countDownTimer.start();
}
};
autoCompleteView.addTextChangedListener(textChecker);
}

Categories

Resources