将EditText聚焦在Device上运行的PopupWindow时出现异常

Mar*_*los 17 java android android-edittext

我正在为Android开发一个PopUp窗口,它正在工作,我在其上添加了一个EditText和一个Button,当在ADV上运行时,这个工作正常,当在设备上运行时,当我专注于EditText时,这会引发一个奇怪的异常.

android.view.WindowManager$BadTokenException: Unable to add window - - token android.view.ViewRoot&48163b18 is not valid; is your active running?
Run Code Online (Sandbox Code Playgroud)

我不知道它是否重要,但我正在运行带有Swype输入的Galaxy Tab.

现在我读了Window.showAtLocation的规范

public void showAtLocation (View parent, int gravity, int x, int y)

Display the content view in a popup window at the specified location. If the popup window cannot fit on screen, it will be clipped. [...]

Parameters
parent  a parent view to get the getWindowToken() token from
[...]
Run Code Online (Sandbox Code Playgroud)

问题只在于该令牌,但我如何将Activity令牌传递给它?

我还写了一个小代码来重现错误.

PopupWindow window = new PopupWindow(activity);
window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);

window.setTouchable(true);
window.setFocusable(true);

EditText text = new EditText(activity);
text.setText("Dont touch, this crash!");

window.setContentView(text);
window.showAtLocation(arg0, Gravity.NO_GRAVITY, 10,10);
Run Code Online (Sandbox Code Playgroud)

在AVD上运行一切正常,而在设备上崩溃并抛出我提到的错误.

我发现了一些新东西,当我处于横向模式时,不会发生这种错误.

kos*_*cki 6

谢谢你,TheRedPill!我在PopupWindow内部的EditText表现出同样的问题.它适用于三星Galaxy S3,HTC One X但在华为MediaPad FHD 10上崩溃了.一旦我开始编辑该应用程序就崩溃了.

你的解决方案

editText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
Run Code Online (Sandbox Code Playgroud)

为我解决了这个问题.

堆栈跟踪是:

08-15 15:49:03.690: ERROR/AndroidRuntime(8692): FATAL EXCEPTION: main
    android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@417eefa8 is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:585)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:326)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
    at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
    at android.view.Window$LocalWindowManager.addView(Window.java:547)
    at android.widget.PopupWindow.invokePopup(PopupWindow.java:988)
    at android.widget.PopupWindow.showAtLocation(PopupWindow.java:845)
    at android.widget.PopupWindow.showAtLocation(PopupWindow.java:809)
    at android.widget.Editor$PinnedPopupWindow.updatePosition(Editor.java:2147)
    at android.widget.Editor$PinnedPopupWindow.show(Editor.java:2104)
    at android.widget.Editor$SuggestionsPopupWindow.show(Editor.java:2349)
    at android.widget.Editor.showSuggestions(Editor.java:1647)
    at android.widget.Editor$1.run(Editor.java:1546)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4745)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    at dalvik.system.NativeStart.main(Native Method)
Run Code Online (Sandbox Code Playgroud)


gor*_*hd1 5

原因:

我将错误的原因追溯到某些手机(Moto Droid Razr 和少数其他 Moto 手机)和一些 android Rom(如某些 CM7 和 CM7.1 ROM)上的拼写自动更正行为。如果文本包含拼写错误的单词,并且文本光标悬停在文本中或文本附近,Android 操作系统将尝试自动调出键盘并尝试提供有关正确拼写的建议。

在大多数设备上,自动更正建议框仅显示为键盘上方的一条线段。但是,在某些自定义 ROM(CM7 是我似乎经常遇到的一种)和某些设备(Droid Razr)上,会出现一个额外的下拉选择框:

看到这个图片什么的自动更正弹出的样子(抱歉没有足够的代表,以插入图片)

我非常怀疑自动更正下拉列表也是作为弹出窗口实现的,它试图使用当前弹出窗口(包含带有拼写错误的 EditText 的那个)作为根视图,并试图获取根视图中的 windowToken。

由于弹出窗口本身不是传统视图,我假设它无法将正确的 windowToken 提供给其他请求它们的视图,因此导致错误。

解决方案:

1) 我能够解决这个问题的最简单方法是使用对话框而不是弹出窗口。他们的 API 非常相似,在我的情况下,使用 Dialog 替换 PopupWindow 相当容易。

例如:

旧代码:

    LayoutInflater inflater = (LayoutInflater) parentActivity.getLayoutInflater();
    View mainView = parentActivity.findViewById(R.id.main_calendar_fragment);
    updateEventPopupWindow = new PopupWindow(inflater.inflate(
            R.layout.add_event_fragment, null, false), metrics.widthPixels, metrics.heightPixels, true);
    updateEventPopupWindow.setBackgroundDrawable(new BitmapDrawable());
    updateEventPopupWindow.showAtLocation(mainView, Gravity.CENTER, 0, 0);
Run Code Online (Sandbox Code Playgroud)

新代码:

    LayoutInflater inflater = (LayoutInflater) parentActivity.getLayoutInflater();
    View mainView = parentActivity.findViewById(R.id.main_calendar_fragment);       
    updateEventDialog = new Dialog(parentActivity, android.R.style.Theme_NoTitleBar);
    updateEventDialog.setContentView(inflater.inflate(R.layout.add_event_fragment, (ViewGroup) mainView, false));
    updateEventDialog.show();
Run Code Online (Sandbox Code Playgroud)

2)第二种方法更难,但如果 PopupWindow 到 Dialog 替换不可行,则可能是合适的,是用户 Fragments 代替 PopupWindows。那里有很多很好的片段教程,所以我不会在这篇文章中费心去讨论如何做到这一点。

3) 作为最后的手段,就像上面提到的多张海报一样,您可以在 PopupWindwow 内的 EditText 字段上关闭文本自动更正以避开这个问题。然而,这会导致糟糕的用户体验,因为许多用户(以及 swype 等键盘)依赖于自动更正,这样做可能会使用户远离您的应用程序。

希望这可以帮助其他面临此问题的人。我把头撞在键盘上超过一天,最后决定尝试 Dialog 方法,令我惊讶的是,它很容易换掉。祝你好运


Dal*_*mas 3

我尝试运行您的代码,但一切对我来说都运行良好...这是我编写的测试类:

public class TestActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button btn = (Button) findViewById(R.id.testBtn);
        btn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v)
            {
                showPopup();
            }
        });
    }


    private void showPopup()
    {
        PopupWindow window = new PopupWindow(this);
        window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
        window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);

        window.setTouchable(true);
        window.setFocusable(true);

        EditText text = new EditText(this);
        text.setText("Touch it, it doesn't crash");

        window.setContentView(text);
        window.showAtLocation(text, Gravity.NO_GRAVITY, 30, 30);
    }
}
Run Code Online (Sandbox Code Playgroud)

主要.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <Button
        android:id="@+id/testBtn"
        android:text="Popup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

也许您尝试在 onCreate() 函数中运行弹出代码?如果我这样做,它会抛出与您相同的异常,但这是正常的,因为调用 onCreate() 时活动尚未完全初始化。

(我也尝试过 Galaxy Tab,但没有 swype 输入)