Android getActivity() Context Goes Stale Over Time in PopupWindow

132 views Asked by At

I have an app that uses a popupWindow for user chat. It is launched from a Fragment, and the supplied context is getActivity(). I will be typing in the popupWindow's multilineEditText and, after about 5 minutes or so, I will consistently get a crash with this error:

android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@d1cf1ec is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:1147)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:471)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:95)
    at android.widget.PopupWindow.invokePopup(PopupWindow.java:1621)
    at android.widget.PopupWindow.showAtLocation(PopupWindow.java:1375)
    at android.widget.PopupWindow.showAtLocation(PopupWindow.java:1341)
    at android.widget.Editor$PinnedPopupWindow.updatePosition(Editor.java:3817)
    at android.widget.Editor$PinnedPopupWindow.show(Editor.java:3773)
    at android.widget.Editor$SuggestionsPopupWindow.show(Editor.java:4287)
    at android.widget.Editor.replace(Editor.java:587)
    at android.widget.-$$Lambda$DZXn7FbDDFyBvNjI-iG9_hfa7kw.run(Unknown Source:2)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:237)
    at android.app.ActivityThread.main(ActivityThread.java:8167)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)

I know this isn't super helpful in explaining the error but, as far as I can tell, this is an issue with getActivity returning null and my popupWindow forcefully detaching from lack of context. Is there any way to avoid and/or fix this issue?

Below is some sample code for help with visualization of the popupWindow issue:

if(getActivity() != null) {

        //Retrieve layout inflater
        LayoutInflater layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (layoutInflater != null) {

            //Inflate custom popup layout
            View inflatedView = layoutInflater.inflate(R.layout.popup_chat_layout, null, false);

            writeMessageEditText = inflatedView.findViewById(R.id.writeMessageEditText);

            chatLayoutManager = new LinearLayoutManager(getActivity());
            //Read from bottom-up
            chatLayoutManager.setStackFromEnd(true);
            chatMessagesRecycler.setLayoutManager(chatLayoutManager);

            popupWindow = new PopupWindow(inflatedView, displayWidth, displayHeight, true);

            popupWindow.setAnimationStyle(R.style.PopupAnimation);

            popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
            popupWindow.setHeight(WindowManager.LayoutParams.MATCH_PARENT);

            popupWindow.showAtLocation(v, Gravity.BOTTOM, 0, 0);

            //Cap message lines - the purpose is not to cap characters, but ONLY to cap length
            writeMessageEditText.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 (writeMessageEditText.getLayout().getLineCount() > 150) {
                        if (writeMessageEditText.getText() != null) {
                            writeMessageEditText.getText().delete(writeMessageEditText.getText().length() - 1, writeMessageEditText.getText().length());
                        }
                        Toast.makeText(getActivity(), "Message may not exceed 150 lines", Toast.LENGTH_SHORT).show();
                    }
                }
            });

            //This was implemented during testing - possible to remove but fine for now
            dismissChatButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    resetAll();
                    previousChat = null;
                    if(popupWindow != null) {
                        popupWindow.dismiss();
                        popupWindow = null;
                    }
                }
            });

        }

    }
1

There are 1 answers

0
Michael Plischke On

Despite being dead-wrong regarding the cause of the core issue I was experiencing, I figure I may as well leave the question up for people who are just as bad at reading stack traces as me.

This may not be the perfect solution but, thanks to Mike M.'s comments, I was able to solve the immediate issue by disabling suggestion popups for the EditText in the xml file like so:

android:inputType="textNoSuggestions"

Otherwise, the solution would be to replace the PopupWindow with a Dialog or Activity.