长按 EditText 崩溃:无法添加 window

Long press EditText crash: Unable to add window

我试图在 EditText 中进行长按,但是当我进行长按时,我收到以下错误。我希望能够长按以获取 Copy/Paste/Select 所有上下文弹出窗口,以便用户可以将文本粘贴到框中。

Fatal Exception: android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@799bfc6 is not valid; is your activity running?

EditText 在 Popup 的 ScrollView 中Window。因此,当错误发生时,我当前在打开 PopupWindow 的 Activity 上处于活动状态,我在 PopupWindow.[=16 中包含的 EditText 中进行长按=]

Gradle 设置

compileSdkVersion 25
buildToolsVersion '25.0.0'
defaultConfig {
    applicationId 'com.accoservice.cico'
    minSdkVersion 17
    targetSdkVersion 25
    versionCode 37
    versionName '4.2.6'
    multiDexEnabled true
}

包含 EditText 的布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/outer_layout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#73000000">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="100dp"
        android:layout_marginBottom="5dp"
        android:background="#ffffff"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="15dp"
            android:singleLine="true"
            android:text="@string/note_msg"
            android:textColor="#62CCFE"
            android:textSize="18sp" />

        <View
            android:layout_width="fill_parent"
            android:layout_height="2dp"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="10dp"
            android:background="#62CCFE" />

        <ScrollView
            android:id="@+id/sv_resolution_note"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_marginTop="5dp">

            <EditText
                android:id="@+id/et_note_msz"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_above="@+id/view"
                android:layout_alignParentTop="true"
                android:scrollbars="vertical"
                android:focusable="true"
                android:gravity="left"
                android:maxLines="20"
                android:hint="@string/write_note"
                android:inputType="textFilter|textMultiLine|textCapSentences"
                android:singleLine="false"
                android:textIsSelectable="true"
                android:enabled="true"
                android:longClickable="true" />
        </ScrollView>

        <View
            android:id="@+id/view"
            android:layout_width="fill_parent"
            android:layout_height="1dp"
            android:layout_above="@+id/send_note"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:background="@android:color/darker_gray" />

        <Button
            android:id="@+id/send_note"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/viewss"
            android:layout_gravity="center"
            android:background="@color/white"
            android:text="@string/add_note" />

        <View
            android:id="@+id/viewss"
            android:layout_width="fill_parent"
            android:layout_height="1dp"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"

            android:background="@android:color/darker_gray" />

    </LinearLayout>

</LinearLayout>

弹出Window:

@Override
public void onClick(View v) {
     noteDialog(getResources().getString(R.string.laborentryresolutionstart), tv_labor_entry_resolution_start);
}

public void noteDialog(String noteTitle, final TextView tv_resolution_note)
{
    LayoutInflater layoutInflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
            final View popupView;
            popupView = layoutInflater.inflate(R.layout.resolution_note, null);

            TextView title = (TextView) popupView.findViewById(R.id.title);
            title.setText(noteTitle);

            final EditText editText = (EditText) popupView.findViewById(R.id.et_note_msz);
            final PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
            popupWindow.update();
            popupWindow.setFocusable(true);
            popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
            editText.setEnabled(false);
            editText.setEnabled(true);
            editText.setFocusable(true);
            editText.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {

                    //ADD HERE ABOUT CUT COPY PASTE
                    // TODO Auto-generated method stub
                    return false;
                }
            });

            if (!tv_resolution_note.getText().toString().isEmpty()) {
                editText.setText(tv_resolution_note.getText().toString());
            }

            Button btnDone = (Button) popupView.findViewById(R.id.send_note);
            LinearLayout outer_layout = (LinearLayout) popupView.findViewById(R.id.outer_layout);
            outer_layout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    popupWindow.dismiss();

                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.toggleSoftInput(InputMethodManager.RESULT_HIDDEN, 0);
                }
            });

            System.gc();
            try {
                btnDone.setOnClickListener(new Button.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        EditText noteMsz = (EditText) popupView.findViewById(R.id.et_note_msz);
                        tv_resolution_note.setText(noteMsz.getText().toString());

                        popupWindow.dismiss();

                        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                        imm.toggleSoftInput(InputMethodManager.RESULT_HIDDEN, 0);

                        invalidateOptionsMenu();
                    }
                });
            } catch (Exception e) {
            }

            popupWindow.setFocusable(true);
            popupWindow.setBackgroundDrawable(new BitmapDrawable(null, ""));
            popupWindow.showAsDropDown(tv_labor_sym_entry, 0, -60);
            popupWindow.update();     
}

您调用弹出窗口可能为时过早。在我的示例 (gist here) 中,我通过按下按钮执行弹出代码。这是在 onCreate() 和其他关键生命周期方法 运行 之后。通过示例,一切正常。

但是,如果我尝试在 onCreate() 中实例化弹出窗口,我会收到一个 logcat 错误,指出:"android.view.WindowManager$BadTokenException: Unable to add window" 这就是您所看到的。

我认为您过早地试图实例化您的弹出窗口。在 activity 的生命周期稍后启动它,并且肯定在 onCreate() 执行之后。如果您需要立即实例化它,您可以通过调用 post(Runnable) 将代码附加到 UI 消息队列。 (参见 here)。

我相当确定这是您的问题。如果这没有帮助,请使用有关如何以及何时实例化弹出窗口的更多信息更新您的问题 window。

根据我的说法,您收到此错误的原因是 outer_layoutonClickListenereditTextonLongClickListener 一起被触发.而且,由于 popupWindow.dismiss 是在 outer_layout 的点击侦听器中调用的,弹出窗口 window 在 editText 的长点击侦听器代码可以 运行 之前被关闭,从而导致错误。

最简单的解决方案是 return true 用于您的 onLongClick 方法:-

editText.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {

                    //ADD HERE ABOUT CUT COPY PASTE
                    // TODO Auto-generated method stub
                    return true;
                }
            });

这样做,您将消耗给定的长按,并且不会触发任何其他不需要的侦听器。

onLongClick() - This returns a boolean to indicate whether you have consumed the event and it should not be carried further. That is, return true to indicate that you have handled the event and it should stop here; return false if you have not handled it and/or the event should continue to any other on-click listeners.

在你的主要 Activity

私有内容 mContext;

public void onCreate(){
 mContext = this;
}

将 getBaseContext() 替换为 mContext

LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);

  LayoutInflater layoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

我们进行了重新设计,去掉了弹出窗口并消除了那里的错误。