2012-06-14 11 views
12

Estoy usando una biblioteca de terceros y, a veces, aparece un cuadro de diálogo. Antes de terminar la actividad actual, quiero verificar si aparece un cuadro de diálogo en el contexto actual.¿Cómo comprobar si la actividad actual tiene un diálogo en el frente?

¿Hay alguna API para esto?

+1

¿Qué biblioteca de terceros está utilizando y qué tipo de aplicación está trabajando? –

Respuesta

7

AFAIK - no hay una API pública para esto.

La forma recomendada es hacer referencia al cuadro de diálogo y verificar isShowing() y llamar al dismiss() si es necesario, pero como está utilizando una biblioteca de terceros, puede que esta no sea una opción para usted.

Su mejor opción es verificar la documentación de la biblioteca que utiliza. Si eso no ayuda, no tienes suerte.

Sugerencia: La actividad cambia al estado "en pausa" si aparece un cuadro de diálogo. Es posible que 'abuse' de este comportamiento;)

+0

¿Hay alguna forma de diálogo id en onpause? – newme

+1

hmm ... Veo su problema ... Puede intentar anular el método onCreateDialog. Deberá mantener una lista de identificadores para los diálogos actualmente abiertos y cerrarlos cuando desee salir. Solo use este método si la biblioteca que está utilizando no lo admite.Puede encontrarse con problemas de la biblioteca de terceros si inesperadamente cierra sus diálogos. (null puntero divertido) – Madushan

+0

Además, tenga en cuenta que este método y el método dismissDialog están en desuso en favor del patrón Fragment. Entonces no diría que es el mejor enfoque. Y parece que no puedes detectar cuándo se cierra un diálogo (excepto que puedes asumirlo cuando la actividad se reanuda desde una pausa. Pero asegúrate de que esto también suceda cuando retires de una pantalla). Así que tendrás que llamar a 'dismissDialog' en todos los identificadores de diálogos conocidos, lo cual es ... bueno ... diría que es ridículo. – Madushan

9

Me enfrenté a un problema similar y no quería modificar todas las ubicaciones donde se creaban y se mostraban los cuadros de diálogo. Mi solución fue ver si la vista que estaba mostrando tenía foco en la ventana a través del método hasWindowFocus(). Esto no funcionará en todas las situaciones, pero funcionó en mi caso particular (esto fue para una aplicación de grabación interna utilizada en circunstancias bastante restringidas).

Esta solución no fue probada minuciosamente por su robustez, pero pensé que podría publicarla en caso de que ayudara a alguien.

+0

Creo que esta es una buena solución para la mayoría de los casos – Pradeep

12

Puede comprobar que se ejecuta sobre los fragmentos activos de esa actividad y comprobar si uno de ellos es DialogFragment, lo que significa que hay un diálogo activo en la pantalla:

public static boolean hasOpenedDialogs(FragmentActivity activity) { 
     List<Fragment> fragments = activity.getSupportFragmentManager().getFragments(); 
     if (fragments != null) { 
      for (Fragment fragment : fragments) { 
       if (fragment instanceof DialogFragment) { 
        return true; 
       } 
      } 
     } 

     return false; 
    } 
+0

Se eliminará DialogFragment descartado de FragmentManager – twlkyao

+0

Veo el momento de pop y move en dismissInternal, pero el método getFragments solo se puede llamar desde el mismo grupo de bibliotecas. – twlkyao

1

estoy suponiendo, que se trata de biblioteca de terceros y no tiene acceso al objeto de diálogo.

Puede obtener la vista raíz de la actividad,

continuación, puede utilizar el algoritmo de recorrido de árbol para ver si se puede llegar a cualquiera de la vista del niño. No debe llegar a ninguna de las vistas de su hijo si se muestra el cuadro de alerta.

Cuando se muestra la vista de alerta (consulte con Ui Automator), el único elemento presente en el árbol de la interfaz de usuario es desde DialogBox/DialogActivity. Puede usar este truco para ver si el cuadro de diálogo se muestra en la pantalla. Aunque suena caro, podría optimizarse.

+0

desde la vista raíz (DecorView) no puede acceder al Diálogo como el cuadro de diálogo en otra ventana. Lo que puedo hacer es desde DecorVie acceder al único miembro que difiere, que es 'mPrivateFlags' y pasa de' 25201976' a '29363512' cuando el diálogo está abierto. El siguiente trabajo es encontrar las banderas útiles adecuadas desde aquí https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java#L1737 debe ser difícil –

+0

hmm, tal vez 'hasWindowFocus' lo haré, pero necesito más pruebas –

6

Esto usa reflexión y API ocultas para obtener las raíces de vista actualmente activas. Si un cuadro de diálogo de alerta muestra esto, se devolverá una raíz de vista adicional. Pero cuidado ya que incluso una ventana emergente de pan tostado devolverá una raíz de vista adicional.

He confirmado la compatibilidad de Android 4.1 a Android 6.0 pero, por supuesto, esto puede no funcionar en versiones de Android anteriores o posteriores.

No he comprobado el comportamiento de los modos de ventanas múltiples.

@SuppressWarnings("unchecked") 
public static List<ViewParent> getViewRoots() { 

    List<ViewParent> viewRoots = new ArrayList<>(); 

    try { 
     Object windowManager; 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 
      windowManager = Class.forName("android.view.WindowManagerGlobal") 
        .getMethod("getInstance").invoke(null); 
     } else { 
      Field f = Class.forName("android.view.WindowManagerImpl") 
        .getDeclaredField("sWindowManager"); 
      f.setAccessible(true); 
      windowManager = f.get(null); 
     } 

     Field rootsField = windowManager.getClass().getDeclaredField("mRoots"); 
     rootsField.setAccessible(true); 

     Field stoppedField = Class.forName("android.view.ViewRootImpl") 
       .getDeclaredField("mStopped"); 
     stoppedField.setAccessible(true); 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 
      List<ViewParent> viewParents = (List<ViewParent>) rootsField.get(windowManager); 
      // Filter out inactive view roots 
      for (ViewParent viewParent : viewParents) { 
       boolean stopped = (boolean) stoppedField.get(viewParent); 
       if (!stopped) { 
        viewRoots.add(viewParent); 
       } 
      } 
     } else { 
      ViewParent[] viewParents = (ViewParent[]) rootsField.get(windowManager); 
      // Filter out inactive view roots 
      for (ViewParent viewParent : viewParents) { 
       boolean stopped = (boolean) stoppedField.get(viewParent); 
       if (!stopped) { 
        viewRoots.add(viewParent); 
       } 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    return viewRoots; 
} 
+1

Ahora solo necesitamos una forma de detectar cuándo ocurrió esa acción. Hasta ahora, parece que 'OnSystemUiVisibilityChangeListener' devuelve la primera vez que aparece un diálogo en una actividad, pero no en las siguientes. Seguiré cavando – VicVu

Cuestiones relacionadas