2012-08-24 15 views
42

Wdrażanie aplikacji, w której użytkownik może się logować Mam następującą sytuację: Jeśli użytkownik jest zalogowany, wykonaj czynność, a następnie rozpocznij działanie logowania dla wyniku, a jeśli wynikiem jest Activity.RESULT_OK wykonaj akcję.Akcje w onActivityResult i "Błąd Nie można wykonać tej akcji po stanie OnSaveInstanceState"

Moim problemem jest to, że działania mające na celu perfom jest pokazanie DialogFragment, ale nazywając

DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel); 
newFragment.show(ft, "dialog") 

w zwrotnego onActivityResult rzuca wyjątek:

Caused by: java.lang.IllegalStateException: 
Can not perform this action after onSaveInstanceState 

Więc jak mogę rozwiązać ten problem? Zastanawiam się w podnoszeniu tam flagę i pokazać okno w onResume ale widzę to rozwiązanie trochę brudny

EDIT: Dodano więcej kodu (Im naśladują tego przykład pokazujący DialogFragment

Gdy działanie jest żądanie użytkownika:

... 
if (!user.isLogged()){ 
startActivityForResult(new Intent(cnt, Login.class), REQUEST_LOGIN_FOR_COMMENT); 
} 

W tym samym fragmencie

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 
    if (requestCode == REQUEST_LOGIN_FOR_COMMENT && resultCode == Activity.RESULT_OK) { 
     FragmentTransaction ft = getFragmentManager().beginTransaction(); 
     DialogFragment newFragment = MyDialogFragment.newInstance(); 
     newFragment.show(ft, "dialog") 
    } 
} 

A jeśli użytkownik loguje się do aktywności Logowanie nazywa;

setResult(Activity.RESULT_OK); 
finish(); 
+0

Myślę, że należy opublikować cały kod. Wygląda na to, że próbujesz wyświetlić okno dialogowe po upływie pewnego czasu. – nandeesh

+0

Edytowane pytanie: D – Addev

+1

Sprawdź http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html, aby zrozumieć, dlaczego tak się dzieje. – Maragues

Odpowiedz

94

Najlepsze, co wymyśliłem, to nie używać .show(), ale raczej robić to.

CheckinSuccessDialog dialog = new CheckinSuccessDialog(); 
//dialog.show(getSupportFragmentManager(), null); 
FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
ft.add(dialog, null); 
ft.commitAllowingStateLoss(); 
+2

Chociaż działa to dla mnie, czuję się niebezpiecznie, ponieważ pominęliśmy dwie zmienne: mDismissed = false; mShownByMe = true; Powyższe zmienne są modyfikowane w oryginalnej funkcji show. –

+2

dziękuję, commitAllowingStateLoss rozwiązał problem dla mnie –

+0

mDyzja i mShowByMe wydają się być zmiennymi specjalnie do śledzenia, czy dialog został pokazany/ukryty przez wywołania zewnętrzne. Innymi słowy, rekompensują dokładnie takie rzeczy. –

9

Oto obejście że działa dobrze dla mnie.

private void alert(final String message) { 
    Handler handler = new Handler(Looper.getMainLooper()); 
    handler.post(new Runnable() { 
     public void run() { 
      AlertDialogFragment alertDialogFragment = AlertDialogFragment.newInstance(message); 
      alertDialogFragment.show(getFragmentManager(), ALERT_DIALOG_FRAGMENT); 
     } 
    });   
} 
4

przypadku korzystania z DialogFragment, jedyną rzeczą, że pracował dla mnie było odrzucenie fragmentu z dissmissAllowingStateLoss()

3

ja po prostu sprawdzić, czy dana działalność jest zniszczona.

if (!getActivity().isFinishing()) { 
    DialogFragment fragment = MyFragment.newInstance(); 
    fragment.show(getActivity().getSupportFragmentManager(), MyFragment.TAG); 
} 
1

Zastąp show(Fragment manager, String tag) funkcja z pozwalając stan stracić i zmienić mDismissed = false;mShownByMe = true; z funkcją origibal przez odbicie:

public class DialogParent extends DialogFragment { 

    @Override 
    public void show(FragmentManager manager, String tag) { 
     try { 
      Field mDismissed = DialogFragment.class.getDeclaredField("mDismissed"); 
      Field mShownByMe = DialogFragment.class.getDeclaredField("mShownByMe"); 
      mDismissed.setAccessible(true); 
      mShownByMe.setAccessible(true); 
      mDismissed.setBoolean(this, false); 
      mShownByMe.setBoolean(this, true); 
     } catch (NoSuchFieldException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
     FragmentTransaction ft = manager.beginTransaction(); 
     ft.add(this, tag); 
     ft.commitAllowingStateLoss(); 
    } 
} 
+0

Można również otoczyć metodę pokazywania rodziców za pomocą try-catch, w której w haczyku dodajesz okno dialogowe i używasz wywołania transakcji 'commitAllowingStateLoss()'. W ten sposób nie potrzebujesz żadnej refleksji. – SimonSimCity

0

To prawdziwe dzieła.

CheckinSuccessDialog dialog = new CheckinSuccessDialog(); 
//dialog.show(getSupportFragmentManager(), null); 
FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
ft.add(dialog, null); 
ft.commitAllowingStateLoss(); 

Ale jednak nadal zła, bo mam błąd „Działalność została zniszczona”

ava.lang.IllegalStateException: Activity has been destroyed fragmentTransaction.commitAllowingStateLoss(); 

Więc moje rozwiązanie jest dodanie sprawdzić if (!isFinishing()&&!isDestroyed())

CheckinSuccessDialog fragment = CheckinSuccessDialog.newInstance(); 

    if (fragment instanceof DialogFragment) { 
       DialogFragment dialog = (DialogFragment) fragment; 
       if (!dialog.isAdded()) { 
        fragmentTransaction.add(dialog, 
          CheckinSuccessDialog.class.getName()); 
        if (!isFinishing()&&!isDestroyed()) { 
         fragmentTransaction.commitAllowingStateLoss(); 
        } 
       } 

na zwolnieniu:

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 
     Fragment fragment = getSupportFragmentManager().findFragmentByTag(CheckinSuccessDialog.class.getName()); 
     if (fragment != null && fragment instanceof DialogFragment) { 
      DialogFragment dialog = (DialogFragment) fragment; 
      dialog.dismiss(); 
      if (!isFinishing()&&!isDestroyed()) { 
       fragmentTransaction.commitAllowingStateLoss(); 
      } 
     } 
0

Ten wyjątek jest t hrown zawsze, gdy FragmentTrasaction zostanie zatwierdzony po zapisaniu stanu przez FragmentManager.Prostym i czystym sposobem jest sprawdzenie, czy FragmentManager już zapisał stan, przed wyświetleniem DialogFragment.

if(!getSupportFragmentManager.isStateSaved()) { 
    MyDialogFragment dialogFragment = new MyDialogFragment() 
    dialogFragment.show(getSupportFragmentManager, TAG); 
} 
Powiązane problemy