我有一个Android编程问题。使用下面的代码我想验证字符串匹配。它验证很好,但LogCat显示TextWatcher方法每次按键触发两次,我无法弄清楚原因。我希望每次按键只能发射一次。
你知道为什么会这样做吗?
我认为这可能是因为我改变了文字的颜色,但在评论之后它并没有什么区别。
LogCat输出
03-31 03:37:25.269: I/BeforeText(676): Hit
03-31 03:37:25.269: I/OnText(676): Hit
03-31 03:37:25.269: I/AfterText(676): Hit
03-31 03:37:25.274: I/InvalidText(676): Incorrect Text.
03-31 03:37:25.274: I/Text Value(676): a
03-31 03:37:25.404: I/BeforeText(676): Hit
03-31 03:37:25.404: I/OnText(676): Hit
03-31 03:37:25.404: I/AfterText(676): Hit
03-31 03:37:25.404: I/InvalidText(676): Incorrect Text.
03-31 03:37:25.404: I/Text Value(676): a
活动代码
public void onCreate(Bundle savedInstanceState) {
//...omitted
//Create Answer Field
textField = (EditText)this.findViewById(R.id.textField);
//Add validation to TextField
textField.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s){
Log.i("AfterText","Hit");
if(textField.getText().toString().trim().equalsIgnoreCase("hello")){
Log.i("ValidText", "Text matched.");
answerField.setTextColor(Color.GREEN);
}
else{
Log.i("InvalidText", "Incorrect text.");
Log.i("Text Value", textField.getText().toString());
textField.setTextColor(Color.RED);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){
//Do nothing
Log.i("BeforeText", "Hit");
}
public void onTextChanged(CharSequence s, int start, int before, int count){
//Do nothing
Log.i("OnText","Hit");
}
});
}
答案 0 :(得分:3)
正如你的问题是针对 TextWatcher方法每按一次键击两次。 您已在EditText上使用TextWather进行Make for Validate String并设置Color。
您可以在此处参阅开发人员网站中的Text for TextWatcher。 http://developer.android.com/reference/android/text/TextWatcher.html
当您按下密钥库时,它将在EditText文本中以TextWatcher方法onTextChanged
调用方式进行更改,当您按下EditText方法beforeTextChanged
的任何键时,这将在我们开始编辑EditText时调用。 / p>
当你在EditText中输入一个字符时,还会调用Textwather
的所有这三个方法。只是调用序列的顺序是不同的。还要重新提出这个问题Android TextWatcher.afterTextChanged vs TextWatcher.onTextChanged < / p>
因此,在EditText中为文本更改调用两次没有错。
希望你明白。
答案 1 :(得分:1)
我不认为这对你有帮助,但在我的情况下它似乎是刷卡键盘。
重点是,当滑动尝试提出建议时,onchange方法似乎被调用两次(一个来自EditText,另一个来自滑动键盘)。
我不知道你的代码是否可行,但只需在你的EditText上试试看看会发生什么:
android:inputType="textNoSuggestions"
您可以查看下一个有关此问题的网站:
如果我找到解决方案,我会编辑这个答案。
我的结论是,我无法避免中间事件,我无法区分用户的真实更改事件或滑动更改事件。
根据您的实际问题,您应该尝试不同的解决方法。一种解决方法可能是保存ConcurrentHashMap中更新的信息,并在收到事件后100毫秒安排任务。同时你应该设置一个“lastModified”日期。
在计划任务中你应该问“从上次更新开始已经过了100毫秒?”,如果答案是否定的 - >什么都不做(这意味着另一个事件已经到达,因此将使用最后一个值执行另一个更新任务)。
使用ReentrantLock完成所有操作以达到原子性。
这样的事情:
private final ReentrantLock lock = new ReentrantLock();
private final ScheduledExecutorService scheduleExecutor = new ScheduledThreadPoolExecutor(1);
private Date lastModification = null;
private static final long UPDATE_WINDOW_IN_MILLISECONDS = 100;
protected class UpdateBusinessLogicTask implements Runnable {
private final String newVal;
public UpdateBusinessLogicTask(String newVal) {
super();
this.newVal = newVal;
}
@Override
public void run() {
//check current date
Date now = new Date();
//get lock to achieve atomicity
lock.lock();
// calculate elapsed time
long elapsedTime = lastModification.getTime() - now.getTime();
// free the lock --> you could free the lock after business logic, depends on your scenario
lock.unlock();
//if the time is less than the updating window (100 milliseconds)
if (elapsedTime < (UPDATE_WINDOW_IN_MILLISECONDS - 1)) {
// DO NOTHING!!
Log.d("TEST", "Dismiss update "+newVal);
} else {
Log.d("TEST", "Updating business with newVal: "+newVal);
// TODO implement business logic
}
}
};
protected void onCreate(Bundle savedInstanceState) {
EditText view = findViewById(R.id.nameEditText);
TextWatcher tw = new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d("TEST", "New text event received, new val: " + s.toString());
lock.lock();
lastModification = new Date();
scheduleExecutor.schedule(new UpdateBusinessLogicTask(s.toString()), UPDATE_WINDOW_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
lock.unlock();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
};
}
答案 2 :(得分:1)
也许你有两个textWatchers,textField.addTextChangedListener方法被调用两次。
答案 3 :(得分:0)
您可以使用布尔值。在用户更改文本时设置它,在自定义代码触发时重置它。该事件仍然会触发两次,但您的代码只调用一次。 最好的问候。
答案 4 :(得分:-1)
使用它,它可能对您有所帮助:
myInput.addTextChangedListener(new TextWatcher() {
boolean mToggle = false;
public void onTextChanged(CharSequence cs, int s, int b, int c) {}
public void afterTextChanged(Editable editable) {
if (mToggle)
Toast.makeText(getBaseContext(), "HIT KEY", Toast.LENGTH_LONG).show();
mToggle = !mToggle;
}
});