2014-12-28 11 views
5

Ho capito che questa domanda è stata posta molte volte qui, ma dopo aver trascorso le ultime 1,5 ore di lettura e cercando di risolvere il problema, non posso.AndroidRuntimeException: requestFeature() deve essere chiamato prima di aggiungere contenuto in DialogFragment

dichiarazione del problema:

Quando si chiama il metodo setStyle in DialogFragment ottengo l'errore RuntimeException indicato nel titolo.

Questo è il mio codice originale, che non genera questa eccezione:

public class MapDialogFragment extends DialogFragment 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     view = inflater.inflate(R.layout.maps_dialog, container, false); 
     return view; 
    } 
} 

ImmersiveMode Ora, ho appena aggiunto per tutta la mia domanda. Come alcuni di voi potrebbero sapere, la modalità immersiva viene persa quando si visualizzano le finestre di dialogo, quindi è necessario scavalcare questi frammenti e impostare i flag appropriati in modo che la modalità venga mantenuta. Ho realizzato con successo questo - funziona. Ma, devo commentare la riga: setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);, quindi sto perdendo lo stile del mio dialogo e questo è il problema.

Avere uno sguardo più da vicino il metodo setStyle nel DialogFragment, non posso davvero vedere come requestFeature() sia invocata:

public void setStyle(int style, int theme) { 
     mStyle = style; 
     if (mStyle == STYLE_NO_FRAME || mStyle == STYLE_NO_INPUT) { 
      mTheme = com.android.internal.R.style.Theme_DeviceDefault_Dialog_NoFrame; 
     } 
     if (theme != 0) { 
      mTheme = theme; 
     } 
    } 

Infine, questa è la mia classe DialogFragment in cui l'eccezione sta accadendo. Si noti la getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); e anche il clearFlag, che erano necessarie per avere l'ImmersiveMode di lavoro (spero che questo sarà utile per qualcuno):

public class MapDialogFragmentv2 extends DialogFragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     //I have also tried the code here, before the super.OnCreate but to no avail 
     //setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo); 
     super.onCreate(savedInstanceState); 
    } 

    @Override 
    public Dialog onCreateDialog(final Bundle savedInstanceState) { 
     MyDialog mDialog = new MyDialog(getActivity()); 

     mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 

     view = getActivity().getLayoutInflater().inflate(R.layout.maps_dialog, null); 

     //Line below throws exception. Needs to be commented out 
     setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo); 
     mDialog.setContentView(view); 

     return mDialog; 
    } 

    public class MyDialog extends Dialog { 
     public MyDialog(Context context) { 
      super(context); 
      getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); 
      getWindow().getDecorView().setSystemUiVisibility(MainActivity.getImmersiveModeFlags()); 
     } 

     @Override 
     public void show() { 
      getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); 
      super.show(); 
     } 
    } 
} 

Inoltre ho provato utilizzando un mix di onCreate, onCreateView e onCreateDialog ma didn' lavoro. Ho anche letto qui su Stackoverflow qualcuno che ha commentato che non era una buona idea avere onCreateView e onCreateDialog allo stesso tempo.

E anche provato ad aggiungere lo stile al mio layout xml per sé, ma anche non ha funzionato:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/lib/com.google.android.gms.plus" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:background="@android:color/transparent" 
    style="@android:style/Theme.Holo.Dialog" > 

Grazie

+0

Hai provato a chiamare setStyle() all'interno onCreate(), ma piuttosto dopo super.onCreate (savedInstanceState)? –

+0

@ dev.bmax sì, l'ho fatto. In effetti, quello era il codice molto originale. –

+0

La tua 'MapDialogFragmentv2' è una classe annidata all'interno di un' Activity'? –

risposta

5

Il problema è che Lei pesta insieme troppe cose diverse e che si non rispettare il ciclo di vita di ogni classe.

In primo luogo è necessario interrompere le classi di nidificazione come si fa. Questa è in parte la fonte dell'errore. Se si desidera realmente/necessario nidificare un numero Fragment o Dialog, è importante dichiarare come statico lo stato nidificato Fragments, Dialogs. Se non li dichiari statici, puoi causare perdite di memoria e problemi come il tuo. Ma la cosa migliore che puoi fare è limitarti a una classe per file, a meno che tu non abbia una ragione reale per annidarla. Questo ha anche il vantaggio di migliorare la leggibilità e la manutenibilità del tuo codice.

Ma la causa principale del tuo errore è che ignori completamente il ciclo di vita di Dialog.Praticamente tutto il seguente codice dovrebbe essere nei metodi propri del ciclo di vita del Dialog:

mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 

view = getActivity().getLayoutInflater().inflate(R.layout.maps_dialog, null); 

//Line below throws exception. Needs to be commented out 
setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo); 
mDialog.setContentView(view); 

Quindi, per risolvere il tuo errore è necessario fare 3 cose:

  1. In entrambi i dichiarare MapDialogFragmentv2 e MyDialog statico come questo:

    public class MainActivity extends Activity { 
    
        ... 
    
        public static class MapDialogFragmentv2 extends Fragment { 
    
         ... 
    
         public static class MyDialog extends Dialog { 
          ... 
         } 
        } 
    } 
    

O meglio ancora spostarli tutti insieme nei propri file.

  1. Spostare il codice onCreateDialog() in MapDialogFragmentv2 nei metodi del ciclo di vita corretti in MyDialog. Dovrebbe quindi essere simile a questa:

    public static class MyDialog extends Dialog { 
    
        private final LayoutInflater mInflater; 
    
        public MyDialog(Context context) { 
         super(context); 
    
         mInflater = LayoutInflater.from(context); 
        } 
    
        @Override 
        protected void onCreate(Bundle savedInstanceState) { 
         super.onCreate(savedInstanceState); 
    
         getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); 
         getWindow().getDecorView().setSystemUiVisibility(MainActivity.getImmersiveModeFlags()); 
    
         View view = mInflater.inflate(R.layout.maps_dialog, null); 
         setContentView(view); 
        } 
    
        @Override 
        public void show() { 
         getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); 
         super.show(); 
        } 
    } 
    
  2. Aggiungere setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo); al metodo del vostro MapDialogFragmentv2onCreate() dopo la chiamata super.onCreate().

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
    
        setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo); 
    } 
    

tuo MapDialogFragmentv2 dovrebbe poi basta guardare in questo modo:

public static class MapDialogFragmentv2 extends DialogFragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo); 
    } 

    @Override 
    public Dialog onCreateDialog(final Bundle savedInstanceState) { 
     return new MyDialog(getActivity()); 
    } 
} 

ho provato tutto sul mio Nexus 5 con sistema operativo Android 5.0.1 (Lollipop) e funziona .

+0

Questo in realtà ha molto senso. Sto cercando di farlo funzionare, ma ancora senza fortuna. Finisco con una finestra di dialogo che non è a schermo intero e non ha lo stile applicato. Credo di aver seguito tutto quello che mi hai detto, ma la mia implementazione è molto più complessa di quello che ho mostrato qui - quindi continuerò a provare. Se funziona seguendo il tuo suggerimento, lo imposterò come corretto. –

0

ho risolto il problema di non avere un dialogo a tutto schermo nel MapDialogFragmentv2:

@Override 
    public void onStart() { 
     super.onStart(); 

     Dialog dialog = getDialog(); 
     if (dialog != null) { 
      int width = ViewGroup.LayoutParams.MATCH_PARENT; 
      int height = ViewGroup.LayoutParams.MATCH_PARENT; 
      dialog.getWindow().setLayout(width, height); 
     } 
    } 

Ora l'unica cosa che manca è che il metodo setStyle() non funziona. Lo stile non è impostato. Ma non getta l'eccezione originale menzionata in questo post.

0

Ok,

E 'quasi ora di lavoro, quindi mi segnerà di Xaver risposta come corretta quanto mi portano alla strada giusta.

ho dovuto cambiare la classe MyDialog a:

MyDialog pubblico (contesto Context, int tema) {
super (contesto, il tema);
mInflater = LayoutInflater.from (contesto);

}

In questo modo riesco a mantenere il tema. Ma per qualche motivo i miei pulsanti non stanno seguendo il tema. Sono tutti di default.Sto cercando di impostare lo stile in modo programmatico, ma senza successo per ora

buttonGuess.setBackgroundColor (android.R.attr.borderlessButtonStyle); buttonOk.setBackgroundColor (android.R.style.Widget_Holo_Button);

Tuttavia, ora funziona come lo voglio.

Grazie a tutti

0

ho risolvere questo problema rimuovere questo codice.

public View onCreateView(LayoutInflater inflater, ViewGroup container, 
                 Bundle savedInstanceState) { 
    return inflater.inflate(R.layout.fragment_choose_image, container, false); 
} 

} 
Problemi correlati