2012-06-14 15 views

risposta

7

AFAIK - non ci sono API pubbliche per questo.

Il modo consigliato è di avere un riferimento alla finestra di dialogo e controllare isShowing() e chiamare dismiss() se necessario, ma poiché si sta utilizzando una libreria di terze parti, questa potrebbe non essere un'opzione per voi.

La soluzione migliore è controllare la documentazione della libreria che si utilizza. Se questo non ti aiuta, sei sfortunato.

Suggerimento: l'attività passa allo stato "in pausa" se viene visualizzata una finestra di dialogo. Potresti essere in grado di "abusare" di questo comportamento;)

+0

c'è un modo per dialogare id in onpause? – newme

+1

hmm ... Vedo il tuo problema .... Puoi provare a sovrascrivere il metodo onCreateDialog. Dovrai mantenere un elenco di ID per le finestre di dialogo attualmente aperte e chiuderle quando vuoi uscire. Utilizza questo metodo solo se la libreria che stai utilizzando non la supporta.Potresti incorrere in problemi della libreria di terze parti se chiudi inaspettatamente le loro finestre di dialogo. (divertimento con il puntatore nullo) – Madushan

+0

Inoltre, si noti che questo metodo e il metodo dismissDialog sono deprecati a favore del pattern Fragment. Quindi non direi che è l'approccio migliore. E sembra che tu non riesca a rilevare quando una finestra di dialogo si chiude (eccetto che puoi assumerla quando l'attività riprende da una pausa.) Ma assicurati che ciò accada anche quando riprendi da uno schermo spento). Quindi dovrai chiamare 'dismissDialog' su tutti gli id ​​di dialogo conosciuti, che è ... beh ... direi ridicolo. – Madushan

9

Ho affrontato un problema simile e non volevo modificare tutte le posizioni in cui venivano create e mostrate le finestre di dialogo. La mia soluzione consisteva nel verificare se la vista che stavo mostrando avesse il focus sulla finestra tramite il metodo hasWindowFocus(). Questo non funzionerà in tutte le situazioni, ma ha funzionato nel mio caso particolare (questo era per un'app di registrazione interna utilizzata in circostanze abbastanza ristrette).

Questa soluzione non è stata accuratamente testata per la robustezza, ma ho pensato di postare nel caso in cui fosse di aiuto a qualcuno.

+0

Penso che questa sia una buona soluzione per la maggior parte dei casi – Pradeep

12

È possibile controllare in esecuzione sui frammenti attivi di tale attività e verificare se uno di loro è DialogFragment, il che significa che c'è una finestra attiva sullo schermo:

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

Il DialogFragment rimosso verrà rimosso da FragmentManager – twlkyao

+0

Vedo il pop e il momento di spostamento in dismissInternal, ma il metodo getFragments può essere chiamato solo dallo stesso gruppo di librerie. – twlkyao

1

Io parto dal presupposto, si tratta di libreria di terze parti e non si ha accesso all'oggetto di dialogo.

È possibile ottenere la vista radice dall'attività,

Quindi è possibile utilizzare l'algoritmo attraversamento albero per vedere se è possibile raggiungere qualsiasi della vista del bambino. Non dovresti raggiungere nessuna delle tue visualizzazioni figlio se viene visualizzata una finestra di avviso.

Quando viene visualizzata la vista di avviso (controllare con Ui Automator), l'unico elemento presente nella struttura dell'interfaccia utente proviene da DialogBox/DialogActivity. Puoi usare questo trucco per vedere se la finestra di dialogo è visualizzata sullo schermo. Anche se sembra costoso, potrebbe essere ottimizzato.

+0

dalla vista radice (DecorView) non è possibile raggiungere la finestra di dialogo poiché la finestra di dialogo si trova in un'altra finestra. Quello che posso fare è che DecorVie acceda al solo membro che differisce, che è "mPrivateFlags" e va da "25201976" a "29363512" quando la finestra di dialogo è aperta. Il prossimo lavoro è trovare le bandiere utili giuste da qui https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/View.java#L1737 dovrebbe essere difficile –

+0

hmm, forse 'hasWindowFocus' lo farò ma ho bisogno di più test –

6

Questo utilizza le API di riflessione e nascoste per ottenere le radici di visualizzazione correntemente attive. Se viene visualizzata una finestra di avviso, verrà restituita una vista aggiuntiva. Ma attento come anche un popup popup restituirà una radice di visualizzazione aggiuntiva.

Ho confermato la compatibilità da Android 4.1 ad Android 6.0 ma ovviamente questo potrebbe non funzionare nelle versioni Android precedenti o successive.

Non ho controllato il comportamento per le modalità multi-finestra.

@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

Ora abbiamo solo bisogno di un modo per rilevare quando quell'azione è avvenuta. Finora sembra che "OnSystemUiVisibilityChangeListener" restituisca la prima volta che una finestra di dialogo viene mostrata su un'attività, ma non in momenti successivi. Continuerò a scavare. – VicVu

Problemi correlati