web-dev-qa-db-fra.com

java.lang.IllegalStateException: impossible d'exécuter cette action après onSaveInstanceState avec DialogFragment

Je rencontre un problème avec DialogFragment/getSupportFragmentManager/Android version 4.x

01-10 19:46:48.228: E/AndroidRuntime(9879): Java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.Java:1314)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.Java:1325)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.Java:548)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.support.v4.app.BackStackRecord.commit(BackStackRecord.Java:532)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.support.v4.app.DialogFragment.show(DialogFragment.Java:127)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions.showDialog(TermsAndConditions.Java:256)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions.handleMessage(TermsAndConditions.Java:62)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.v1.mypck.TermsAndConditions$IncomingHandler.handleMessage(TermsAndConditions.Java:53)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.os.Handler.dispatchMessage(Handler.Java:99)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.os.Looper.loop(Looper.Java:137)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Android.app.ActivityThread.main(ActivityThread.Java:4441)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Java.lang.reflect.Method.invokeNative(Native Method)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at Java.lang.reflect.Method.invoke(Method.Java:511)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:784)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:551)
01-10 19:46:48.228: E/AndroidRuntime(9879):     at dalvik.system.NativeStart.main(Native Method)

Dans le code ci-dessous, lorsque j'appuie sur, il essaie de terminer l'activité en cours et revient à l'activité précédente, il renvoie l'erreur ci-dessus.

Le code fonctionne bien sur les anciennes versions (antérieures à 4.x).

Quelqu'un peut-il me guider dans la bonne direction.

public class TermsAndConditions extends SherlockFragmentActivity implements LoaderManager.LoaderCallbacks<JSONObject>{
    static final String TAG = "TermsAndConditions";
    private static int titleResource;
    private static int messageResource;

    private IncomingHandler handler = null;
    private static final int SHOW_NETWORK_DIALOG = 3;

    static class IncomingHandler extends Handler {
        private final WeakReference<TermsAndConditions> mTarget; 

        IncomingHandler(TermsAndConditions target) {
            mTarget = new WeakReference<TermsAndConditions>(target);
        }

        @Override
        public void handleMessage(Message msg) {
            TermsAndConditions target = mTarget.get();
            if (target != null) {
                target.handleMessage(msg);
            }
        }
    }
    public void handleMessage(Message msg) {
        switch (msg.what)  {
            case SHOW_NETWORK_DIALOG:
                titleResource = R.string.msg_alert_no_network_title;
                messageResource = R.string.msg_alert_no_network_message;
                showDialog();
                break;
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.web_view);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportLoaderManager().initLoader(0, null, this);
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case Android.R.id.home:
                finish();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
    private void loadViewData() {
        //Logic to load content.
    }

    @Override
    public Loader<JSONObject> onCreateLoader(int arg0, Bundle arg1) {
        if (handler == null){
            handler = new IncomingHandler(TermsAndConditions.this);
        }
        return new JsonLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<JSONObject> arg0, JSONObject jsonData) {
        if(jsonDataObject==null || jsonDataObject.length()==0) {
            handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
        } else {
            loadViewData();
        }
    }

    @Override
    public void onLoaderReset(Loader<JSONObject> arg0) {
        if(jsonDataObject==null || jsonDataObject.length()==0) {
            handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
        } else {
            loadViewData();
        }
    }

    public static class JsonLoader extends AsyncTaskLoader<JSONObject> {
        public JsonLoader(Context context) {
            super(context);
        }

        @Override 
        protected void onStartLoading() {
            if (jsonDataObject != null) {
                deliverResult(jsonDataObject);
            }
            if (takeContentChanged() || jsonDataObject == null) {
                forceLoad();
            }
        }

        @Override
        public JSONObject loadInBackground() {
            try {
                return response.getJSONObject("result");
            } catch (JSONException e) {
                return null;
            } catch (Throwable e) {
                return null;
            }
        }

        @Override 
        public void deliverResult(JSONObject newJsonData) {
            if (isReset()) {
                if (jsonDataObject != null) {
                    onReleaseResources(jsonDataObject);
                }
            }
            JSONObject oldData = jsonDataObject;
            jsonDataObject = newJsonData;
            if (isStarted()) {
                super.deliverResult(jsonDataObject);
            }
            if (oldData != null) {
                onReleaseResources(oldData);
            }
        }

        @Override 
        protected void onStopLoading() {
            cancelLoad();
        }

        @Override public void onCanceled(JSONObject jsonData) {
            super.onCanceled(jsonData);
            onReleaseResources(jsonData);
        }

        @Override protected void onReset() {
            super.onReset();
            onStopLoading();
            if (jsonDataObject != null) {
                onReleaseResources(jsonDataObject);
                jsonDataObject = null;
            }
        }

        protected void onReleaseResources(JSONObject jsonData) {
            jsonData = null;
        }
    }
    public static class MyAlertDialogFragment extends DialogFragment {
        public static MyAlertDialogFragment newInstance(int title) {
            MyAlertDialogFragment frag = new MyAlertDialogFragment();
            Bundle args = new Bundle();
            args.putInt("title", title);
            frag.setArguments(args);
            return frag;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            int title = getArguments().getInt("title");
            return new AlertDialog.Builder(getActivity())
                    .setTitle(title)
                    .setMessage(messageResource)
                    .setPositiveButton(R.string.alert_dialog_ok,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {

                            }
                        }
                    )
                    .create();
        }
    }
    public void showDialog() {
        DialogFragment newFragment = MyAlertDialogFragment.newInstance(titleResource);
        newFragment.show(getSupportFragmentManager(), "my_dialog");
    }
}
34
Yogesh

Voici la réponse dans un autre fil:

Actions dans onActivityResult et "Error Impossible d'exécuter cette action après onSaveInstanceState"

ici aussi:

Rafraîchir mon fragment ne fonctionne pas comme je le pensais

Voici un exemple pour résoudre ce problème:

DialogFragment loadingDialog = createDialog();

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                    transaction.add(loadingDialog, "loading");
                    transaction.commitAllowingStateLoss();  
48
Khaled Annajar

J'ai le même problème et j'ai changé le code comme ci-dessous

newFragment.show(transactionFragment, "dialog");

à:

transactionFragment.add(Android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();

le code terminé fonctionne bien pour moi en tant que soufflet, j'espère que l'aide

FragmentTransaction transactionFragment = getActivity().getSupportFragmentManager().beginTransaction();
    DialogPageListFragment newFragment = new DialogPageListFragment();
    transactionFragment.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    newFragment.setArguments(extras);
    transactionFragment.add(Android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();
8
Tran Khanh Tung

Le gestionnaire qui répond au HandleMessage est probablement associé à une activité détruite.

c'est-à-dire: si vous faites pivoter l'écran, l'ancienne activité détruite gérera le message, puis vous appellerez showDialog, et l'exception sera levée:

Vous créez une boîte de dialogue après que l'ancienne activité détruite a appelé son onSaveInstanceState.

Essayez de remplacer le rappel, par la nouvelle activité créée, pour vous assurer que vous créez la boîte de dialogue toujours dans l'activité vivante.


Si vous ne faites pas de rotation, placez un indicateur sur onSaveInstance comme "enregistrer" et désactivez-le sur onRestoreInstance. Dans votre méthode handleMessage, si l'indicateur "save" est activé, n'affichez pas la boîte de dialogue, activez simplement un autre indicateur indiquant que la boîte de dialogue doit être créée sur onResume. Ensuite, sur la méthode onResume, vérifiez si au milieu de ce processus, vous devez créer la boîte de dialogue, si oui, affichez-la sur la méthode onResume.

5
noni
fragmentView.post(() -> {
    FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
    YourDialog yourDialog = YourDialog.newInstance();
    yourDialog.show(ft, "text_data");
});

Le but de la méthode post () dans ce cas est d'attendre la fin de onResume () de l'activité ou du fragment. Cela fonctionne si vous souhaitez afficher DialogFragment from Fragment., F.e. lorsque vous souhaitez afficher votre boîte de dialogue après la fermeture d'une boîte de dialogue système.

4
Maksim

J'étais confronté au même problème lors du post-retardement de Runnables handler.postDelayed (Runnable runnable, long delay).

J'ai résolu le problème de cette façon:

  1. Dans onSaveInstanceState, j'annule les tâches retardées
  2. Dans onRestoreInstanceState, je recrée la tâche s'il y a eu des tâches retardées lorsque l'activité a été détruite
2
user2832184

réponse trop tardive mais peut être la bonne réponse. J'ai créé une classe parente et un fragment de dialogue en part

 public class BaseDialogFragment extends DialogFragment {

@Override
public void show(FragmentManager manager, String tag) {
    try {
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag).addToBackStack(null);
        ft.commitAllowingStateLoss();
    } catch (IllegalStateException e) {
        Log.d("ABSDIALOGFRAG", "Exception", e);
    }
}

boolean mIsStateAlreadySaved = false;
boolean mPendingShowDialog = false;

@Override
public void onResume() {
    onResumeFragments();
    super.onResume();
}

public void onResumeFragments(){
    mIsStateAlreadySaved = false;
    if(mPendingShowDialog){
        mPendingShowDialog = false;
        showSnoozeDialog();
    }
}

@Override
public void onPause() {
    super.onPause();
    mIsStateAlreadySaved = true;
}

private void showSnoozeDialog() {
    if(mIsStateAlreadySaved){
        mPendingShowDialog = true;
    }else{
        FragmentManager fm = getFragmentManager();
        BaseDialogFragment snoozeDialog = new BaseDialogFragment();
        snoozeDialog.show(fm, "BaseDialogFragment");
    }
}

}

1
mostafa hashim

Vous pouvez vérifier si l'activité actuelle estActive () et uniquement dans ce cas démarrer la transaction de fragment de DialogFragment. J'ai eu un problème similaire et cette vérification a résolu mon cas.

0
box

onPostResume () utilisez la méthode post resume pour faire votre travail .. Je pense que vous appelez la méthode show dialog dans onRestart ou onResume, alors évitez-la et utilisez onPostResume () pour afficher votre dialogue.

0
Vikas Kumbhar

Ça marche:

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

Mais mais toujours mauvais, car l'erreur "L'activité a été détruite"

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

Donc ma solution est d'ajouter check 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();
                    }
                }

en cas de licenciement:

  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
Serg Burlaka