Exception when focusing a EditText in a PopupWindo

2020-06-08 16:39发布

I'm developing a PopUp window for Android, and it's working, I added a EditText and a Button on that, when running on ADV this work properly, while running on device, when I focus on the EditText this throws a weird Exception.

android.view.WindowManager$BadTokenException: Unable to add window - - token android.view.ViewRoot&48163b18 is not valid; is your active running?

I don't know if it matters, but I'm running on a Galaxy Tab with Swype input.

Now I read the specs of the 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
[...]

The problem is just in that token, but how do I pass the Activity token to it?

I also wrote a small code to reproduce the error.

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);

Running on AVD all works fine, while on device this crash and throw the error I mentioned.

I discover something new, when I'm in landscape mode this errors don't occurs.

7条回答
做自己的国王
2楼-- · 2020-06-08 17:22

The cause:

I trace the cause of the error down to the spelling auto-correct behavior on some phones (Moto Droid Razr and few other Moto Phones) and some android Rom (like some CM7 and CM7.1 ROMS). If the text contain a word that is incorrectly spell, and the text cursor is hovering in or near the text, the android OS will try automatically bring up the keyboard and try to provide suggestions on a correct spelling.

On most devices, the auto correct suggestion box only appear as a one line segment above the keyboard. However on some custom ROMs (CM7 being one I seem a lot happening to) and some devices (Droid Razr), there is an additional drop down selection box that appear :

See this image of what the auto-correct popup looks like (sorry not enough rep to insert image)

I highly suspect that the auto correct drop-down list is also implemented as a popup window, and it is trying to use the current popup (the one containing the EditText with the mis-spell word) as the root view, and trying to get the windowToken from the root view.

Since the popup itself is not a traditional view, I am assuming it is unable to give the correct windowToken to other views who are asking for them, therefore leading to the error.

The Solutions:

1) The easiest way I been able to get around this problem is by using Dialog instead of Popup windows. Their API is really similar and in my cases are fairly easy to replace PopupWindow using Dialog.

For example:

Old code:

    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);

New code:

    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();

2) The second approach is harder, but might be a suitable if PopupWindow to Dialog replacement is not doable, is to user Fragments in place of PopupWindows. There are many good fragment tutorials out there, so I won't bother to go over how to do this in this post.

3) As a last resort, like multiple posters mentioned above, you can turn-off text auto correct on the EditText fields inside the PopupWindwow to side step this problem. However this lead to horrible user experiences, since many users (and keyboards like swype) relies on auto-correct, doing this will likely drive user away from your application.

Hope this helps other out there who are facing this problem. I banged my head against the keyboard for over a day before finally decided to try the Dialog approach, which to my surprise was fairly easy to swap out. Best of luck to you

查看更多
仙女界的扛把子
3楼-- · 2020-06-08 17:27

Thank you, TheRedPill! I had the same problem with EditText inside PopupWindow behaving stragely. It worked on Samsung Galaxy S3, HTC One X but crashed on Huawei MediaPad FHD 10. As soon as I started editing the application crashed.

Your solution:

editText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);

Solved the issue for me.

The stack-trace was:

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)
查看更多
劳资没心,怎么记你
4楼-- · 2020-06-08 17:30

Edited

try like this create a new class say Popupcls

  public class PopUpFlag {
        private PopupWindow pw;

    public void initiatePopupWindow(Activity ctx) {
     LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View layout = inflater.inflate(R.layout.popupprofile,  (ViewGroup) ctx.findViewById(R.id.popup_element));
    EditText ettext = (EditText) layout.findViewById(R.id.edit);
    pw = new PopupWindow(layout, 300, 400, true);
    pw.showAtLocation(layout, Gravity.BOTTOM, 0, 0);
    }

Now in your activity if you need popup when popup button click write like this

popupbtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                PopUpFlag puf=new PopUpFlag();
                puf.initiatePopupWindow(YourActivityName.this);
            }
        });

I hope this helps

查看更多
姐就是有狂的资本
5楼-- · 2020-06-08 17:31

The crash occurs on an EditText placed in the WindowManager when user taps on a word underlined as red. Such a underlined word means that it does not exist in the dictionary. On the tap, OS tries to show up a pop with closest matching words from the dictionary and crashes since such a pop up can't be attached to the window due to bad token exception.

Only the following solution seemed to work for me programmatically

//assume an EditText object with name myEditText
myEditText.setInputType(myEditText.getInputType() | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);

InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS does not seem to work as expected on all keyboards whereas InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD has the drawback that it also disables toggling the language in the keyboard and the swipe gesture to add the text.

查看更多
手持菜刀,她持情操
6楼-- · 2020-06-08 17:32

I also got the same error when the edittext in my popupwindow had some text already present and the text wasn't a dictionary word (for e.g. a city name). When I click in between the text and boom! I got the exception. I solved it by making the edittext not show auto correct suggestions:

android:inputType="textNoSuggestions"
查看更多
冷血范
7楼-- · 2020-06-08 17:39

I tried to run your code but everything works fine for me... Here is the test class I wrote :

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);
    }
}

main.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>

Maybe you tried to run the popup code in the onCreate() function? If I do it, it throws the same Exception as yours, but it's normal since when onCreate() is called the activity is not fully initialized yet.

(I tried on a Galaxy Tab too, but without swype input)

查看更多
登录 后发表回答