如何在不触发Text Watcher的情况下更改EditText文本?

时间:2012-02-21 21:00:19

标签: java android event-handling infinite-loop

我有一个EditText字段,上面有一个Customer Text Watcher。在一段代码中,我需要使用.setText("whatever")更改EditText中的值。

问题是,一旦我进行了更改,调用的afterTextChanged方法就会创建一个无限循环。如何在不触发afterTextChanged的情况下更改文本?

我需要afterTextChanged方法中的文字,所以不建议删除TextWatcher

17 个答案:

答案 0 :(得分:80)

您可以查看当前具有焦点的视图,以区分用户和程序触发的事件。

EditText myEditText = (EditText) findViewById(R.id.myEditText);

myEditText.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (getCurrentFocus() == myEditText) {
            // is only executed if the EditText was directly changed by the user
        }
    }

    //...
});

修改:正确提及LairdPleng,如果myEditText已经具有焦点且您以编程方式更改文本,则此功能无效。因此,在致电myEditText.setText(...)之前,您应该将myEditText.clearFocus()称为Chack,这也解决了这个问题。

答案 1 :(得分:55)

您可以取消注册观察者,然后重新注册。

或者,您可以设置一个标记,以便您的观察者知道您何时自己更改了文本(因此应该忽略它)。

答案 2 :(得分:20)

et_text.addTextChangedListener(new MyTextWatcher(et_text));

用法:

{u'definitions': [{u'text': u'One venerated for experience, judgment, and wisdom.', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}, {u'text': u'Having or exhibiting wisdom and calm judgment.', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}, {u'text': u'Proceeding from or marked by wisdom and calm judgment:  sage advice. ', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}, {u'text': u'Archaic   Serious; solemn.', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}, {u'text': u'Any of various plants of the genus Salvia, especially S. officinalis, having aromatic grayish-green, opposite leaves. Also called ramona.', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}, {u'text': u'The leaves of this plant used as a seasoning.', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}, {u'text': u'Any of various similar or related plants in the mint family.', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}, {u'text': u'Sagebrush.', u'attribution': u'from The American Heritage\xae Dictionary of the English Language, 4th Edition'}]}

如果您使用 editText.setText()而不是 editable.replace(),则在快速输入文本时可能会感到有些滞后。

答案 3 :(得分:13)

简单的解决方法...... 只要你的逻辑推导出新的编辑文本值是幂等的(它可能会,但只是说)。在侦听器方法中,如果当前值与上次修改值不同,则仅修改编辑文本。

如,

TextWatcher tw = new TextWatcher() {
  private String lastValue = "";

  @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) {

    // Return value of getNewValue() must only depend
    // on the input and not previous state
    String newValue = getNewValue(editText.getText().toString());
    if (!newValue.equals(lastValue)) {
      lastValue = newValue;

      editText.setText(newValue);
    }
  }
};

答案 4 :(得分:3)

如果您需要专注于EditText更改文字,您可以请求关注。这对我有用:

if (getCurrentFocus() == editText) {
    editText.clearFocus();
    editText.setText("...");
    editText.requestFocus();
}

答案 5 :(得分:2)

我使用这种方式:

mEditText.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 (mEditText.isFocused()) { //<-- check if is focused 
                    mEditText.setTag(true);
                }
            }
        });

每次您需要以编程方式更改文本时,请先清除焦点

mEditText.clearFocus();
mEditText.setText(lastAddress.complement);

答案 6 :(得分:1)

尝试这个逻辑: 我想setText(&#34;&#34;)而不去无限循环,这段代码适合我。我希望你能修改它以符合你的要求

        final EditText text= (EditText)findViewById(R.id.text);
        text.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(s.toString().isEmpty())return;
            text.setText("");
            //your code
        }
    });

答案 7 :(得分:0)

我的变体:

public class CustomEditText extends AppCompatEditText{
    TextWatcher l;

    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public void setOnTextChangeListener(TextWatcher l) {
        try {
            removeTextChangedListener(this.l);
        } catch (Throwable e) {}
        addTextChangedListener(l);
        this.l = l;
    }

    public void setNewText(CharSequence s) {
        final TextWatcher l = this.l;
        setOnTextChangeListener(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) {

            }
        });
        setText(s);
        post(new Runnable() {
            @Override
            public void run() {
                setOnTextChangeListener(l);
            }
        });
    }


}

仅使用setOnTextChangeListener()设置侦听器,并仅使用setNewText设置文本(我想覆盖setText(),但它是最终的)

答案 8 :(得分:0)

我创建了一个抽象类,它减轻了通过TextWatcher对EditText进行修改时的循环问题。

/**
 * An extension of TextWatcher which stops further callbacks being called as a result of a change
 * happening within the callbacks themselves.
 */
public abstract class EditableTextWatcher implements TextWatcher {

    private boolean editing;

    @Override
    public final void beforeTextChanged(CharSequence s, int start, int count, int after) {
        if (editing)
            return;

        editing = true;
        try {
            beforeTextChange(s, start, count, after);
        } finally {
            editing = false;
        }
    }

    abstract void beforeTextChange(CharSequence s, int start, int count, int after);

    @Override
    public final void onTextChanged(CharSequence s, int start, int before, int count) {
    if (editing)
        return;

        editing = true;
        try {
            onTextChange(s, start, before, count);
        } finally {
            editing = false;
        }
    }

    abstract void onTextChange(CharSequence s, int start, int before, int count);

    @Override
    public final void afterTextChanged(Editable s) {
        if (editing)
            return;

        editing = true;
        try {
            afterTextChange(s);
        } finally {
            editing = false;
        }
    }    

    public boolean isEditing() {
        return editing;
    }

    abstract void afterTextChange(Editable s);
}

答案 9 :(得分:0)

这是一个方便的类,它提供了一个比TextWatcher更简单的接口,用于希望在发生更改时查看更改的正常情况。它还允许忽略OP请求的下一个更改。

public class EditTexts {
    public final static class EditTextChangeListener implements TextWatcher {
        private final Consumer<String> onEditTextChanged;
        private boolean ignoreNextChange = false;
        public EditTextChangeListener(Consumer<String> onEditTextChanged){
            this.onEditTextChanged = onEditTextChanged;
        }
        public void ignoreNextChange(){
            ignoreNextChange = true;
        }
        @Override public void beforeTextChanged(CharSequence __, int ___, int ____, int _____) { }
        @Override public void onTextChanged(CharSequence __, int ___, int ____, int _____) { }
        @Override public void afterTextChanged(Editable s) {
            if (ignoreNextChange){
                ignoreNextChange = false;
            } else {
                onEditTextChanged.accept(s.toString());
            }
        }
    }
}

像这样使用:

EditTexts.EditTextChangeListener listener = new EditTexts.EditTextChangeListener(s -> doSomethingWithString(s));
editText.addTextChangedListener(listener);

每当您想修改editText的内容而不会导致一连串的递归编辑时,请执行以下操作:

listener.ignoreNextChange();
editText.setText("whatever"); // this won't trigger the listener

答案 10 :(得分:0)

您可以使用Kotlin DSL语法为此提供通用解决方案:

fun TextView.applyWithDisabledTextWatcher(textWatcher: TextWatcher, codeBlock: TextView.() -> Unit) {
    this.removeTextChangedListener(textWatcher)
    codeBlock()
    this.addTextChangedListener(textWatcher)
}

在TextWatcher中,您可以将其用作:

editText.applyWithDisabledTextWatcher(this) {
    text = formField.name
}

答案 11 :(得分:0)

这对我有用

EditText inputFileName; // = (EditText)findViewbyId(R.id...)
inputFileName.addTextChangedListener(new TextWatcher() {
        public void afterTextChanged(Editable s) {

            //unregistering for event in order to prevent infinity loop
            inputFileName.removeTextChangedListener(this);

            //changing input's text
            String regex = "[^a-z0-9A-Z\\s_\\-]";
            String fileName = s.toString();
            fileName = fileName.replaceAll(regex, "");
            s.replace(0, s.length(), fileName); //here is setting new text

            Log.d("tag", "----> FINAL FILE NAME: " + fileName);

            //registering back for text changes
            inputFileName.addTextChangedListener(this);
        }

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

        public void onTextChanged(CharSequence s, int start, int before, int count) { }
    });

答案 12 :(得分:0)

使用tag字段可以轻松解决问题,您甚至不必处理editText的焦点。

以编程方式设置文本和标签

editText.tag = "dummyTag"
editText.setText("whatever")
editText.tag = null

检查onTextChanged中的tag

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
    if (editText.tag == null) {
       // your code
    }
}

答案 13 :(得分:0)

非常简单,使用此方法设置文本

document.querySelector('script').addEventListener('beforeinclude', function(e){
  //Function executed before each tag like <script src="path/to/jquery.min.js"> be included
})

答案 14 :(得分:0)

这样做很容易

editText.addTextChangedListener(object : TextWatcher {

        private var isEditing = false

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


        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

        }

        override fun afterTextChanged(s: Editable?) {
            if(!isEditing){
                isEditing = true
                editText.setText("Hello World!")
                isEditing = false
            }

        }
    })

通过这种方式,它不会无限循环存储

答案 15 :(得分:-2)

您应该确保文本更改的实现是稳定的,并且如果不需要更改则不会更改文本。通常,这将是已经通过观察者一次的任何内容。

最常见的错误是在关联的EditText或Editable中设置新文本,即使文本实际上没有更改。

最重要的是,如果您对可编辑视图进行了更改而不是某些特定视图,则可以轻松地重新使用您的观察者,并且您可以单独使用某些单元测试来测试它,以确保它具有您想要的结果。

由于Editable是一个接口,你甚至可以使用它的虚拟实现,如果在测试应该稳定的内容时调用任何试图改变其内容的方法,则抛出RuntimeException。

答案 16 :(得分:-2)

我做事的方式:

在写段中

        EditText e_q;

        e_q = (EditText) parentView.findViewWithTag("Bla" + i);

        int id=e_q.getId();
        e_q.setId(-1);
        e_q.setText("abcd...");
        e_q.setId(id);

听众

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

        int id = view.getId();
        if(id==-1)return;

        ....

仍然可以工作。