调用 popupwindow 的 showAtLocation 会使应用程序崩溃

calling showAtLocation of popupwindow is crashing the app

我有 class 从 View 延伸而来,我正在尝试使用此代码

显示 popupWindow
public class dbView extends View implements View.OnTouchListener {

    private void showDialog(String msg) {
        LayoutInflater layoutInflater;
        View dialogContent;
        final PopupWindow popupWindow;

        layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        dialogContent = layoutInflater.inflate(R.layout.pop_up_dialog, null);

        popupWindow = new PopupWindow(
                dialogContent,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);

        popupWindow.showAtLocation(this, Gravity.CENTER, 10, 10);

    }

}

我的应用程序在尝试执行最后一行时崩溃了。异常信息为

Can't create handler inside thread that has not called Looper.prepare()

我已经寻找与该消息相关的答案,所有答案都涉及弹出窗口是在单独的线程上创建的,我应该使用 runOnUIThread 但如果我在 VIEW 中,我需要这样做吗?这个问题的原因可能是什么?

我想这可能是因为您试图从非原始线程(创建 UI)干扰您的 UI。您的自定义视图 class 无权更改 UI,因此我认为最好的方法是调用 runOnUIThread()。虽然我听说使用 runOnUIThread 可能不是最佳选择,但在我看来,这正是您所需要的。

通常为了让它工作,我做了一个特殊的 class 扩展应用程序(在我的例子中它是 ContextGetter)并实现这样的方法:

public class ContextGetter extends Application {

    private static Context context;

    public void onCreate(){
        super.onCreate();
        context = getApplicationContext();
    }

    public static Context getAppContext() {
        return context;
    }
}

它帮助我从任何地方获取应用上下文。您还应该像这样将它添加到您的清单中:

<application
        android:name=".ContextGetter"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

并在此标签中包含您的所有活动。

当你有你的上下文时,你可以做这件事:

((Activity)ContextGetter.getAppContext()).runOnUiThread(new Runnable()
{
//doSomethingInside
});

它可能看起来很奇怪,但它一定对你有用。它看起来是这样的,因为 Activity 是从 Context 派生的。每当您尝试时,我都想知道它是否有效。希望我对问题有所帮助

这取决于您在哪里调用 showDialog(String msg),我知道您是从视图 class 调用它,但这并不意味着它在 UI 线程上,视图调用在 UI 线程上处理,但如果您在线程中进行视图调用,您将遇到该错误。我知道相同的代码可以自行解决,但是如果您在 View class 中运行 TimerTask 或 Threads,您应该仔细检查它们。此外,您可以在视图 class 中调用 post(runnable);(相同的机制 Handler),而不是 runOnUithread,这将确保可运行的调用将被发送到 Main线程。

简而言之,请检查您在 View class

中调用它的位置

在清单中

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

您可以通过 window 管理器自行修复它。

private void showCustomPopupMenu()
{
            windowManager2 = (WindowManager)getSystemService(WINDOW_SERVICE);
            LayoutInflater layoutInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view=layoutInflater.inflate(R.layout.xxact_copy_popupmenu, null);
            params=new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.TYPE_PHONE,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    PixelFormat.TRANSLUCENT);

            params.gravity=Gravity.CENTER|Gravity.CENTER;
            params.x=10;
            params.y=10;
            windowManager2.addView(view, params);  
}