Android Retain Dialog verschwindet beim drehen

Natac

Bekanntes Mitglied
Ich haben ein DialogFragment, dass mit einem AsyncTask verbunden ist, weswegen ich [c]retain[/c] für das Fragment auf TRUE setze.

DialogFragment.java
Java:
public class Dialog extends DialogFragment{
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);// Flag setzen
    }
    
    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
      final LayoutInflater inflater = getActivity().getLayoutInflater();
      final View dialogContent = inflater.inflate(R.layout.dialog, null);
      final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
      builder.setPositiveButton("Close", null);

      //TODO: hier task starten
      
      return builder.create();
    }
}

MyActivity.java
Java:
public class MyActivity extends Activity {

public boolean onOptionsItemSelected(final MenuItem item) {
   // Show dialog on any selection (for testing)
   final DialogFragment dialog = new Dialog();
   dialog.show(getFragmentManager(), "dialog");
   return true;
}

protected void onRestoreInstanceState(final Bundle state) {
  super.onRestoreInstanceState(state);  

  final DialogFragment dialog = (DialogFragment) getFragmentManager().findFragmentByTag("dialog");
  if (dialog != null) { // WTF? dialog ist IMMER NULL
    dialog.show(getFragmentManager(), "dialog");//re-show dialog
  }
}

Ich zeige den Dialog an, und wenn sich das Tablet dreht, zeige ich ihn erneut an... theoretisch. Praktisch scheint der FragmentManager aber gar nichts von meinem DialogFragment zu wissen und gibt jedesmal null zurück, womit der Dialog natürlich nicht erscheint.

Irgend jemand eine Idee? :rtfm:
 
Zuletzt bearbeitet:

dzim

Top Contributor
Nur aus purem Interesse: Hast du es mal so hier probiert?
Java:
DialogFragment dialog = new DialogFragment();
getFragmentManager().beginTransaction().add(dialog , "dialog").commit();
getFragmentManager().executePendingTransactions();
dialog.show(getFragmentManager());

// ............
// woanders dann

DialogFragment dialog = (DialogFragment) getFragmentManager().findFragmentByTag("dialog");
if (...)...
 

Natac

Bekanntes Mitglied
Aha... nachdem ich heute noch ein wenig Google bemüht habe, bin ich zu folgender Erkenntnis gekommen:

Ich bin diesem Bug zum Opfer gefallen. Nachdem ich diesem Hinweis gefolgt bin, komm ich nun zu folgendem Workaround, der auch funktioniert:

Dialog.java
Java:
public class Dialog extends DialogFragment {
  // Code as above
  
  public void onDestroyView() {
        if ((getDialog() != null) && getRetainInstance()) {
            getDialog().setDismissMessage(null);
        }
        super.onDestroyView();
    }
}

Warum genau das jetzt funktioniert erschließt sich mir noch nicht gänzlich, aber es geht. Hoffen wir mal, dass es so bleibt und sich auch auf dem Produktivgerät so verhält.


@dzim: Deine Lösung habe ich probiert, und sie funktioniert nicht.
 
Zuletzt bearbeitet:

dzim

Top Contributor
@Natac: War auch nur eine Idee. Ich habe mich mit dem Retain noch nie beschäftigt. Da ich meistens mit der Support-Lib arbeite, kann ich dir nur danken, die Lösung gepostet zu haben - das spart mir das suchen, wenn ich mal so was benötige ;-)
 

Natac

Bekanntes Mitglied
So... jetzt funktioniert es, aber leider wieder nur mit einem Workaround, da der Bugfix ein Problem mit sich bringt: Öffnet man den Dialog erneut und dreht das Tablet, so kommt eine IllegalStateException, die ich auch nach einigen frustreichen Versuchen nicht wegbekommen habe. Daher hier jetzt meine aktuelle Lösung, die zwar nicht so schön ist, zumindest aber funktioniert:

activity.xml
[XML]...
<LinearLayout android:id="@+id/fragment_target" ></LinearLayout>
...
[/XML]

MyActivity.java
Java:
protected void onCreate(final Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity);
  
  this.fragment = (DialogFragment) getFragmentManager().findFragmentByTag("dialog");
  
  if (this.fragment == null) {
    this.fragment = new DialogFragment();
    getFragmentManager().beginTransaction().add(R.id.fragment_target, this.fragment, "dialog").commit();
  }
}

DialogFragment.java
Java:
public class DataUpdateFragment extends Fragment {
   private AsyncTask<?, ?, ?> task;
   private AlertDialog dialog;
  
    @Override
    public void onCreate(final Bundle savedState) {
        super.onCreate(savedState);
        setRetainInstance(true);
    }
    
    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);
        if (this.task != null) {
            showDialog();
        }
    }
    
    @Override
    public void onDetach() {
        if (this.dialog != null) {this.dialog.dismiss();}
        super.onDetach();
    }

     public void showDialog() {
        final LayoutInflater inflater = getActivity().getLayoutInflater();
        final View dialogContent = inflater.inflate(R.layout.dialog, null);
        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setPositiveButton("Close", null);
        this.dialog = builder.create();
          
        if (this.task == null) {this.task = new MyTask(this).execute();}
        this.dialog.show();
     }

     protected void closeDialog() {
        this.dialog.dismiss();
        this.task = null;
        this.dialog = null;
    }
    
   private static final class UpdateTask extends AsyncTask<...>{
        DialogFragment fragment;

         public UpdateTask(final DialogFragment fragment) {
            this.fragment = fragment;
         }
         // implement doInBackground()
         protected void onPostExecute(...) {this.fragment.closeDialog(); }
         protected void onCancelled() {this.fragment.closeDialog(); }
}

Damit melde ich das Fragment als (unsichtbare) Komponente an, und zeige den Dialog immer neu, wenn das Tablet gedreht wird. Unschön, aber anders scheint es erstmal nicht zu gehen. Wenn jemandem da was eleganteres einfällt, dann darf er sich hier gerne melden ;)
 

Ähnliche Java Themen

Neue Themen


Oben