I have class that extends from a View
and I am trying to show a popupWindow
using this code
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);
}
}
My app is crashing when trying to execute that last line. The message of the exception is
Can't create handler inside thread that has not called Looper.prepare()
I have looked for answers related to that message and all of them involve that the popup was being created on a separate thread and that I should use
runOnUIThread
but If I am inside a VIEW do I need to to this ? What can be the cause of this problem ?
It depends on where you are calling showDialog(String msg)
, i know you were calling it from your View class, but that does not mean its on the UI thread, View calls are processed on the UI thread, but if you make a View call in a Thread you will have that error. i know the same code solved itself, but if you are runing TimerTask or Threads in your View class you should double check them. And also instead of runOnUithread
you can call post(runnable);
(the same mechanism Handler
) in your View class, that will make sure that the runnable call will be sent to the Main thread.
In short check where you calling it in your View
class
I suppose it may be caused because you're trying to interfere to your UI from non-original thread (that created the UI). Your custom view class doesn't have acess to changing the UI so I think that the best way to do that is to call runOnUIThread()
. Though I have heard that using runOnUIThread
may be not the best choice but it seems to me that this will be exactly what you need in your case.
Usually to get this working I make a special class that extends Application (in my case it's ContextGetter) and implement a method like this:
public class ContextGetter extends Application {
private static Context context;
public void onCreate(){
super.onCreate();
context = getApplicationContext();
}
public static Context getAppContext() {
return context;
}
}
It helps me to get the app context from everywhere. You should also add it to your manifest like this:
<application
android:name=".ContextGetter"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
and include all your activities inside this tag.
When you have your context you can do this thing:
((Activity)ContextGetter.getAppContext()).runOnUiThread(new Runnable()
{
//doSomethingInside
});
It may look strange but it must work for you. It looks this way because Activity
is derived from Context
. Whenever you try it I'd like to know if it worked. Hope I helped with the question
in manifest
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
you can fixed it by making your own through the window manager.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With