PopupWindow里面的WebView中的上下文菜单/窗口崩溃了应用程序?

时间:2013-03-30 05:30:36

标签: android android-webview android-contextmenu

我有一个包含WebView的PopupWindow打开Facebook页面的应用程序,任何上下文菜单如:WebView中的文本字段上的自动完成,甚至长按,应该显示用户复制/粘贴/剪切的选项崩溃应用程序马上就出现以下错误:

FATAL EXCEPTION: main
android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@418cdab0 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:700)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:345)
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:554)
at android.widget.PopupWindow.invokePopup(PopupWindow.java:1013)
at android.widget.PopupWindow.showAtLocation(PopupWindow.java:856)
at android.widget.PopupWindow.showAtLocation(PopupWindow.java:820)
at android.webkit.WebViewClassic$PastePopupWindow.show(WebViewClassic.java:971)
at android.webkit.WebViewClassic.showPasteWindow(WebViewClassic.java:7037)
at android.webkit.WebViewClassic.access$10300(WebViewClassic.java:235)
at android.webkit.WebViewClassic$PrivateHandler.handleMessage(WebViewClassic.java:11376)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
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:1027)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
at dalvik.system.NativeStart.main(Native Method)

注意:我对问题的理解是,上下文菜单/窗口实际上显示在应用程序本身的范围内,而不是使用另一个PopWindow(由Core WebView类生成的自动)在WebView内部这个类错误地引用了上下文。

我的代码如下:

main.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/openpopup"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Open Popup Window" />

</LinearLayout>

Popup.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/background_light"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_margin="1dp"
        android:background="@android:color/darker_gray"
        android:orientation="vertical" >
     >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_margin="20dp"
            android:orientation="vertical" >

            <WebView
                xmlns:ptr="http://schemas.android.com/apk/res-auto"
                android:id="@+id/webviewActionView"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:minHeight="200dp"
                android:minWidth="200dp"
                android:scrollbars="none" >
            </WebView>

            <Button
                android:id="@+id/dismiss"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:text="Dismiss" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

MainActivity.java

import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.PopupWindow;

public class MainActivity extends Activity {

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

        final Button btnOpenPopup = (Button) findViewById(R.id.openpopup);
        btnOpenPopup.setOnClickListener(new Button.OnClickListener() {

            @SuppressLint("NewApi")
            @Override
            public void onClick(View arg0) {

                LayoutInflater layoutInflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
                View popupView = layoutInflater.inflate(R.layout.popup, null);
                final PopupWindow popupWindow = new PopupWindow(popupView,
                        LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);

                popupWindow.setTouchable(true);
                popupWindow.setFocusable(true);

                WebView popupWebview = (WebView) popupView.findViewById(R.id.webviewActionView);
                popupWebview.loadUrl("https://m.facebook.com");
                Button btnDismiss = (Button) popupView
                        .findViewById(R.id.dismiss);
                btnDismiss.setOnClickListener(new Button.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                        // TODO Auto-generated method stub
                        popupWindow.dismiss();
                    }
                });
                popupWindow.showAsDropDown(btnOpenPopup, 50, -30);
            }
        });
    }
}

3 个答案:

答案 0 :(得分:6)

如上面在我的回答中所述,您可以使用自定义对话框来满足您的要求..我已经创建了一个示例PopupDialog ..请检查并告诉我..如果它解决了您的目的..自动完成和ContextMenus将按预期工作。

MyActivity.java

package com.example.testapp;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;

public class MyActivity extends Activity {

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

    final Button btnOpenPopup = (Button) findViewById(R.id.openpopup);
    btnOpenPopup.setOnClickListener(new Button.OnClickListener() {

        @SuppressLint("NewApi")
        @Override
        public void onClick(View arg0) {

            final PopupDialog popupDialog = new PopupDialog(MyActivity.this);
            popupDialog.setContentView(R.layout.popup);

            WebView popupWebview = (WebView) popupDialog.findViewById(R.id.webviewActionView);
            popupWebview.setWebChromeClient(new WebChromeClient());
            popupWebview.setWebViewClient(new WebViewClient());

            popupWebview.loadUrl("http://m.facebook.com");
            Button btnDismiss = (Button) popupDialog
                    .findViewById(R.id.dismiss);
            btnDismiss.setOnClickListener(new Button.OnClickListener() {
                @Override
                public void onClick(View v) {

                    // TODO Auto-generated method stub
                    popupDialog.dismiss();
                }
            });
//                popupDialog.showAtLocation(50,50);
            popupDialog.showAsDropDown(findViewById(R.id.openpopup));
        }
    });
}
}

PopupDialog.java

package com.example.testapp;

import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public class PopupDialog extends Dialog{
private final Context mContext;

public PopupDialog(Context context) {
    super(context);
    mContext=context;
    requestWindowFeature(Window.FEATURE_NO_TITLE);
}

public void showAtLocation(int x,int y)
{
    WindowManager.LayoutParams wmlp = getWindow().getAttributes();
    wmlp.gravity = Gravity.TOP | Gravity.LEFT;
    wmlp.x = x;
    wmlp.y = y;
    show();
}
public void showAsDropDown(View view)
{
    float density = mContext.getResources().getDisplayMetrics().density;
    WindowManager.LayoutParams wmlp = getWindow().getAttributes();
    int[] location = new int[2];
    view.getLocationInWindow(location);
    wmlp.gravity = Gravity.TOP | Gravity.LEFT;
    wmlp.x = location[0]+(int)(view.getWidth()/density);
    wmlp.y = location[1]+(int)(view.getHeight()/density);
    show();
}
}

编辑:添加了popup.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:minHeight="400dp"
          android:minWidth="200dp"
          android:background="@android:color/background_light"
          android:orientation="vertical" >

<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_margin="1dp"
        android:background="@android:color/darker_gray"
        android:orientation="vertical" >
    >

    <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_margin="20dp"
            android:orientation="vertical" >

        <WebView
            xmlns:ptr="http://schemas.android.com/apk/res-auto"
                android:id="@+id/webviewActionView"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:minHeight="200dp"
                android:minWidth="200dp"
                android:scrollbars="none" >
        </WebView>

        <Button
                android:id="@+id/dismiss"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:text="Dismiss" />
    </LinearLayout>
</LinearLayout>

答案 1 :(得分:2)

是的,我认为您应该使用您的活动名称代替“getBaseContext()”。我刚刚用你的代码创建了一个演示。它在我的电脑上工作正常。当你得到这个例外时?

答案 2 :(得分:1)

您的代码没有错误。似乎是Android 4.1+特定问题.. Webview也使用PopupWindow在输入框中显示粘贴上下文菜单。通过webview的嵌套弹出窗口导致WindowManager崩溃,同时向其添加新视图。

我尝试使用嵌入式Webview的自定义对话框(代替Popupwindow),在Android 4.1 +中粘贴上下文菜单正常。

如果您对此粘贴上下文菜单没有那么具体,您可以使用以下代码禁用它为特定的Android版本..我已经尝试过了..它会阻止应用程序崩溃..

  popupWebView.setOnLongClickListener(new OnLongClickListener() {

        @Override
        public boolean onLongClick(View v) {
            if (Build.VERSION.SDK_INT >= 16)
                  return true;
              return false;
        }
    });

此外,您可以根据需要查看Webview HitTestResult课程以显示一些自定义的上下文菜单。