调用 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);
}
我有 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);
}