安卓上InputConnection处于非活动状态的getExtractedText警告

146
我在logcat中发现了以下警告。
getExtractedText on inactive InputConnection

我无法找到背后的原因,请帮忙。


4
我不明白这个问题中有什么含糊、模糊或不完整的地方?在运行我的应用程序时,我在我的logcat中收到了这个警告,我想知道这个警告的原因。 - pankajagarwal
4
我在开发的应用程序中也遇到了这个问题,但不知道它的来源或原因。如果有人找到答案,请留言评论。除了"getExtractedText"之外,它实际上显示了许多不同的警告,例如:"beginBatchEdit"、"endBatchEdit"、"getTextBeforeCursor"等等。 - span
1
管理员是否正在查看这个问题。如果没有,那么他们应该这样做,因为即使在获得14个赞之后,如果他们仍然认为这个问题模糊不清,我也不知道该说什么了。 - pankajagarwal
3
你有什么代码导致了这个错误? - Bill the Lizard
这可以通过登录对话框示例进行复制 http://developer.android.com/guide/topics/ui/dialogs.html#CustomLayout 选择对话框中的文本字段,然后更改屏幕方向。 - wreckgar23
显示剩余7条评论
14个回答

49

我遇到了类似的问题。我的日志:

W/IInputConnectionWrapper(21214): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(21214): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(21214): getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper(21214): getTextAfterCursor on inactive InputConnection
...
I/Choreographer(20010): Skipped 30 frames!  The application may be doing too much work on its main thread.

我的情况:

我有一个用户可以输入的EditText视图。当用户按下按钮时,EditText将被清除。当我快速按下按钮时,大量不活动的InputConnection条目会流出。

例如:

editText.setText(null);

上面logcat中的最后一行提供了很好的指示,确实,InputConnection被请求清除文本所压倒。我尝试修改代码,在尝试清除之前检查文本长度:
if (editText.length() > 0) {
    editText.setText(null);
}

这有助于缓解问题,即快速按下按钮不再引起IInputConnectionWrapper警告流。然而,当用户快速在输入文本和按下按钮之间交替或在应用程序负载足够大时按下按钮仍容易出现问题。
幸运的是,我找到了另一种清除文本的方法:Editable.clear()。这样我就完全没有警告了。
if (editText.length() > 0) {
    editText.getText().clear();
}

请注意,如果您希望清除所有输入状态而不仅仅是文本(自动文本、自动大写、多点触控、撤销),您可以使用 TextKeyListener.clear(Editable e)
if (editText.length() > 0) {
    TextKeyListener.clear(editText.getText());
}

1
我也遇到了IInputConnectionWrapper警告,我的应用程序几乎ANR,但是clear()方法对我有用...超级奇怪的错误,在此之前我设置了setText("")。 - box

22

更新:

我出现InputConnection警告的原因并不是因为我在哪里设置文本(例如,在onTextChanged回调中或者afterTextChanged中)——而是因为我使用了setText

我通过调用以下方法来解决这个问题:

hiddenKeyboardText.getText().clear();
hiddenKeyboardText.append("some string");
注意:尽管没有来自“ontextChanged”的警告,但我仍然在afterTextChanged回调中进行调用。
以前的回答:
我在日志窗口也收到了与此相同的消息,但我的情况略有不同。 我想读取进入EditText的每个字符(或组成字符/粘贴文本),然后将问题中的EditText重置为默认初始化字符串。
清除文本部分按照Johnson的解决方案正常工作。 但是,重置文本是有问题的,我会收到输入连接警告。
最初,我的onTextChanged(CharSequence s, ...)定义如下:
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    if (isResettingKeyboard)
        return;

    // ... do what needs to be done

    resetKeyboardString();

}

public void resetKeyboardString()
{
    isResettingKeyboard = true;

    hiddenKeyboardText.getText().clear();
    hiddenKeyboardText.setText(keyboardInitString);
    hiddenKeyboardText.setSelection(defaultKeyboardCursorLocation);

    isResettingKeyboard = false;
}

当调用onTextChanged(...)时,EditText处于只读模式。我不确定这是否意味着我们不能对其进行更多操作,除了调用getText.clear()(调用setText(...)也会产生inputConnection警告)。

然而,afterTextChanged(Editable s)回调是设置文本的正确位置。

@Override
public void afterTextChanged(Editable s) {

    if (isResettingKeyboard)
        return;

    resetKeyboardString();

    // ... 
}

到目前为止,这个工作没有出现任何警告。


我也遇到了同样的问题。我意识到,虽然你的解决方案消除了InputConnection警告,但我注意到afterTextChanged方法在hiddenKeyboardText.getText().clear();hiddenKeyboardText.append("some string");上都被调用,这一事实也应该被考虑进去。给你点赞! - Nick
@Nick true -- 重要的是确保 if (isResettingKeyboard) return; 在顶部... - ahash

10
我曾经遇到了同样的问题。当软键盘在我的一个EditText中被激活并且活动失去焦点时,出现了警告。
我所做的是在onPause()中隐藏键盘。
@Override
protected void onPause() {

    // hide the keyboard in order to avoid getTextBeforeCursor on inactive InputConnection
    InputMethodManager inputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);

    inputMethodManager.hideSoftInputFromWindow(myEditText.getWindowToken(), 0);

    super.onPause();
}

3
这就是答案。确保在从当前屏幕上的活动切换之前隐藏键盘。 - Gábor

7
从帮助文档中

http://developer.android.com/reference/android/view/inputmethod/InputConnection.html

InputConnection接口是从输入法到接收其输入的应用程序之间的通信渠道。它用于执行诸如读取光标周围的文本、提交文本到文本框和向应用程序发送原始键事件等操作。此外,进一步阅读显示:getExtractedText()方法可能会失败,如果输入连接变得无效(例如其进程崩溃)或客户端在回复文本方面花费太长时间(给予几秒钟返回),则将返回null。它似乎还监视此类文本的更改,并提醒更改发生。要解决问题,您需要探索正在进行的任何数据库查询,例如布局中的listViews或列表。如果您没有任何视图,例如在后台随机发生,则建议忽略文本字段等UI元素问题。可能是一个后台服务,在游标中存储信息或请求游标引起的。另外,问题是否来自您的应用程序?还是最近安装的其他人的应用程序?列出完整的logCat跟踪。有人可能认识这个问题。
我猜想,如果您没有针对此问题编写特定的内容,那么这可能是其他人的日志信息,或者是您正在使用的库的信息?

1
谢谢,我确实会进行数据库查询,但奇怪的是,在模拟器上运行应用时没有出现这个警告,所以可能是由于我设备上安装的其他应用程序导致的。会朝这个方向进行调查。 - pankajagarwal
我认为最新的logCat会将你的消息与其他应用程序进行区分和过滤。但是我还没有足够的使用经验来确认这一点。您可以创建一个新的空应用程序,并观察日志记录以查看是否发生错误,这将排除您的应用程序作为问题的原因。 - Emile
@frieza 不一定是其他应用程序。我已经使用sqlite添加了ArrayAdapter,现在手机上也出现了这个警告。我猜你在模拟器上看不到错误是因为它很慢,性能阈值被禁用了。 - alandarev

3

除了antoniom的答案外,确保在隐藏键盘后,确实完成了需要进行的任何进一步操作,因此,如果您已经像下面这样隐藏了键盘:

public void hideKeyboard() {
InputMethodManager inputMethodManager =(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
}

键盘隐藏后需要执行以下操作,如下所示:

getWindow().getDecorView().post(new Runnable() {            
        @Override
        public void run() {
            finish(); //Sample succeeding code
     }
});

1

我不知道为什么会在构建过程中初始化控制器,但我确实这样做了。

 `Widget build(BuildContext context) {
 final _formKey = GlobalKey<FormState>();
 final prodName = TextEditingController();
 final prodDesc = TextEditingController();
 final prodPrice = TextEditingController();
 ...` 

代替,取代
`final _formKey = GlobalKey<FormState>();
 final prodName = TextEditingController();
 final prodDesc = TextEditingController();
 final prodPrice = TextEditingController();
 ...
 Widget build(BuildContext context) {`

当我将控制器和全局键正确地放置到我的表单中时,所有问题(如预期)都消失了!


1
我解决了这个问题,也许你有同样的问题。
这是由于在列表适配器HeaderView中的Object引起的。
我使用inflate方法创建了一个View,并声明了该对象,并对其进行了TextWatcher监听。
View v = LayoutInflater.from(CONTEXT).inflate(R.layout.in_overscrollview, null);
Object= (Object) v.findViewById(R.id.OBJECT_ID);

Object.addTextChangedListener(new TextWatcher() {
        @Override
        public void afterTextChanged(Editable s) {
        }

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

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        //Do my work
        //Update my view
        }
});

将其添加到列表适配器中并构建适配器。

JobListView = (ListView) getListView().findViewWithTag("JOBLISTVIEWTAG");
JobListView.addHeaderView(v, null, false);
JobsAdapter = new IN_JOBS_ADAPTER(CONTEXT, ITEMS_FOR_ADATER);
ListView.setAdapter(JOBSadapter);

一切都很好,文本监视器发挥了作用。

但是,如果我在初始构建之后重新构建适配器。

JobsAdapter = new IN_JOBS_ADAPTER(CONTEXT, DIFFERENT_ITEMS_FOR_ADAPTER);
ListView.setAdapter(JOBSadapter);

那个HeaderView也被重新构建了。
警告会出现是因为Object已被移除,而Text Watcher仍在监听它。 List AdapterObject被替换了,我猜Text Watcher在发生这件事时没有注意到。
所以警告会触发并且奇迹般地Text Watcher找到了HeaderViewObject。但它失去了焦点并记录了那个警告。
使用
JOBSadapter.notifyDataSetChanged();

问题已经解决。

但是,如果您在适配器内部有一个对象,并且文本监视器附加到适配器内部的对象。 那么您可能需要做更多的工作。

尝试删除监听器,并在完成任何工作后重新附加它。

Object.removeTextChangedListener();

或者

Object.addTextChangedListener(null);

0
我的问题是由于每次用户键入一个字符时,将 EditText 的可见性设置为 GONE ,然后立即将其设置为 VISIBLE ,因为我每次文本更改时都在验证输入,并且在某些情况下需要隐藏视图。
因此,解决方案是避免在UI或状态更新之间将View或Layout的可见性设置为GONE,因为 EditText 可能会失去焦点。

0
我解决了我的问题,通过在xml中插入一个输入类型,像这样: android:inputType="none|text|textCapWords|textUri"
之前是android:inputType="text" 这解决了我的问题。

4
对我没有任何帮助。 - DSlomer64

0

清空EditText之前隐藏软键盘 - 这样不会显示警告。

另外,这似乎是与设备有关。我只在Nexus 4(Android 7.1)上看到过它。在模拟器(8.0、7.1)或Nexus 5上没有警告。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接