Android EditText:通过setText()或键盘输入区分文本更改

Android EditText:通过setText()或键盘输入区分文本更改,android,input,android-edittext,Android,Input,Android Edittext,我有一个EditText视图,该视图由我的代码中的setText()编辑,由用户通过(软/硬)键盘编辑,如果可能,还可以通过语音输入编辑。我想用另一种方式来处理我的代码所做的输入,而不是普通的用户输入:如果发生了用户输入,将触发一个内部事件。但我不知道如何区分两者。以前-在emulator上开发时-我使用onKeyDown()方法捕获用户输入。然而,当在真实设备上测试时,我发现,onKeyDown()不是由软键盘输入触发的。另外,语音输入不会被这一点所承认,尽管我认为这是一个小瑕疵。所以这个解决

我有一个
EditText
视图,该视图由我的代码中的
setText()
编辑,由用户通过(软/硬)键盘编辑,如果可能,还可以通过语音输入编辑。我想用另一种方式来处理我的代码所做的输入,而不是普通的用户输入:如果发生了用户输入,将触发一个内部事件。但我不知道如何区分两者。以前-在emulator上开发时-我使用
onKeyDown()
方法捕获用户输入。然而,当在真实设备上测试时,我发现,
onKeyDown()
不是由软键盘输入触发的。另外,语音输入不会被这一点所承认,尽管我认为这是一个小瑕疵。所以这个解决方案对我来说是没有选择的


另一方面,有
onTextChanged()
方法,但这是由
setText()
和键盘输入触发的。那么,我如何区分这两种方法,或者哪种方法只由用户输入调用,而不是在使用
setText()
时调用,那么我可以覆盖它吗?

我相信android不允许您区分编程输入的文本和手动输入的文本。对于您来说,唯一的解决办法是使用一些sla来指示测试是何时由您的代码设置的,因为您总是知道何时调用setText()。

我最终通过实现一个
InputConnectionWrapper
解决了这个问题(参见问题,特别是实现示例的答案)它有多种方法从软键盘获取输入。我在方法
EditText.onCreateInputConnection()
中返回我的
InputConnectionWrapper
。对于硬键盘,我使用
EditText.onPreIme()
。所有这些方法都被覆盖,并通过我的框架传递它们的输入,该框架处理文本输入并相应地更新视图。这意味着,在所有这些被覆盖的方法中(除了
onCreateInputConnection()
),超级方法不会被调用,因为我自己更新了视图。这可以防止我的数据模型和视图之间的不一致。

您可以使用标志来区分

((EditText) rootView.findViewById(R.id.editText1)).addTextChangedListener(new TextWatcher() {
        public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        }

        public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        }

        public void afterTextChanged(Editable editable) {
            update(true);
        }
    });            

private boolean updating = false;

private void update(boolean multiply) {
    if(updating){
        return;
    }
    updating = true;
    EditText editText1 = (EditText) getView().findViewById(R.id.editText1);
    editText1.setText("XXX");
    updating = false;
}

我在旋转设备时遇到了这个问题。我的编辑文本在对话框中。我是这样解决的:

editText.addTextChangedListener(
    new TextWatcher() {

        @Override
        public void afterTextChanged(Editable s) {
            String newValue = s.toString();

           String oldValue = (String) editText.getTag();

            if (newValue.length() > 0) {
                editText.setTag(newValue);
            }

            boolean itReallyChanged = oldValue != null && !newValue.equals(oldValue) && !newValue.isEmpty();
            if (itReallyChanged) {
                // Pretty sure the user genuinely changed this value,
                // not the device rotation
            }
        }
    }
);

这里已经有很多好的解决办法了!我想补充一些对我有用的东西,让将来可能有这个问题的人可以选择

我使用了TextWatcher,只是在编辑EditText时检查当前有焦点的元素。请注意,如果在您的应用程序中,用户必须在输入文本之前将焦点放在EditText上(例如,通过单击它),并且当您在代码中使用
setText
时,您可以确定另一个元素将具有焦点,那么这将起作用

像这样的

yourEditText.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) {
                    if (yourEditText.hasFocus) {
                        //this is a user input
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            }
    );

是的,我也想到了一个布尔指示符变量,但是setText()和用户输入可能同时发生,所以这不能正常工作。但是为什么需要区分不同的输入源呢?正如我上面解释的,当用户更改某些文本时,我想触发一个事件。但是,如果文本被代码更改,则不能激发此事件。如果不锁定EditText,则无法实现所需的内容,但我不确定是否允许。请尝试将onTextChangedListener和flag组合起来。只要所有编辑都在一个线程内,onTextChangedListener事件将排队,您可以尝试分析标志。itReallyChanged?:)