android - personalizado - llamar a ShowAtLocation de popupwindow está bloqueando la aplicación
pop up android studio (3)
Tengo una clase que se extiende desde una View
y estoy tratando de mostrar una popupWindow
usando este código
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);
}
}
Mi aplicación se bloquea al intentar ejecutar esa última línea. El mensaje de la excepción es
No se puede crear el controlador dentro de la secuencia que no ha llamado a Looper.prepare ()
He buscado respuestas relacionadas con ese mensaje y todas ellas implican que la ventana emergente se creó en un hilo separado y que debería usar runOnUIThread
pero si estoy dentro de una vista, ¿necesito hacerlo? ¿Cuál puede ser la causa de este problema?
Supongo que puede deberse a que estás tratando de interferir con tu UI a partir de un hilo no original (que creó la UI). Su clase de vista personalizada no tiene acceso para cambiar la interfaz de usuario, así que creo que la mejor manera de hacerlo es llamar a runOnUIThread()
. Aunque he oído que usar runOnUIThread
puede no ser la mejor opción, pero me parece que esto será exactamente lo que necesita en su caso.
Por lo general, para que esto funcione, hago una clase especial que amplía la Aplicación (en mi caso es ContextGetter) e implemento un método como este:
public class ContextGetter extends Application {
private static Context context;
public void onCreate(){
super.onCreate();
context = getApplicationContext();
}
public static Context getAppContext() {
return context;
}
}
Me ayuda a obtener el contexto de la aplicación desde cualquier lugar. También debería agregarlo a su manifiesto de esta manera:
<application
android:name=".ContextGetter"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
e incluye todas tus actividades dentro de esta etiqueta.
Cuando tienes tu contexto, puedes hacer esto:
((Activity)ContextGetter.getAppContext()).runOnUiThread(new Runnable()
{
//doSomethingInside
});
Puede parecer extraño, pero debe funcionar para usted. Se ve de esta manera porque Activity
se deriva de Context
. Siempre que lo intentes me gustaría saber si funcionó. Espero que haya ayudado con la pregunta
Depende de dónde llame al showDialog(String msg)
, sé que lo estaba llamando desde su clase View, pero eso no significa que esté en el subproceso UI, las llamadas View se procesen en el subproceso UI, pero si hace una Vista llamar en un hilo que tendrá ese error. Sé que el mismo código se resolvió solo, pero si está ejecutando TimerTask o Threads en su clase View, debe verificarlos dos veces. Y también en lugar de runOnUithread
puede llamar a la post(runnable);
(el mismo Handler
mecanismo) en su clase de vista, que se asegurará de que la llamada ejecutable se envíe al hilo principal.
En resumen, ¿dónde lo llamaste en tu clase View
en manifiesto
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
puedes arreglarlo haciendo tu propio a través del administrador de ventanas.
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);
}