Android TextWatcher Firing

时间:2012-03-31 03:57:45

标签: android textwatcher

我有一个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");

        }
    });
}

5 个答案:

答案 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"

您可以查看下一个有关此问题的网站:

http://support.swiftkey.net/forums/116693-2-bug-reports/suggestions/2994580-span-exclusive-exclusive-spans-cannot-have-a-zero-

如果我找到解决方案,我会编辑这个答案。


修改


我的结论是,我无法避免中间事件,我无法区分用户的真实更改事件或滑动更改事件。

根据您的实际问题,您应该尝试不同的解决方法。一种解决方法可能是保存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;
    }
});