web-dev-qa-db-fra.com

java.lang.IllegalStateException: impossible d'effectuer cette action après onSaveInstanceState

J'utilise la bibliothèque de support pour mon application. Dans mon FragmentActivity, j'utilise une AsyncTask pour télécharger des données depuis Internet. Dans la méthode onPreExecute (), j'ajoute un fragment et dans la méthode onPostExecute (), je le supprime à nouveau. Lorsque l'orientation est modifiée entre les deux, j'obtiens l'exception mentionnée ci-dessus. S'il vous plaît jeter un oeil sur les détails:

private class onFriendAddedAsyncTask extends AsyncTask<String, Void, String> {
    DummyFragment dummyFragment; 
    FragmentManager fm;
    FragmentTransaction ft;

@Override
protected void onPreExecute() {
    Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute");
    dummyFragment = DummyFragment.newInstance();
    fm = getSupportFragmentManager();
    ft = fm.beginTransaction();
    ft.add(dummyFragment, "dummy_fragment");
    ft.commit();
}

@Override
protected void onPostExecute(String result) {
    Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute");
    ft = fm.beginTransaction();
    ft.remove(dummyFragment);
    ft.commit();
}

@Override
protected String doInBackground(String... name) {
    Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/doInBackground");
    ...
}

Je reçois LogCut suivant:

01-05 23:54:19.958: V/MyFragmentActivity(12783): onFriendAddedAsyncTask/onPreExecute
01-05 23:54:19.968: V/DummyFragment(12783): onAttach
01-05 23:54:19.968: V/DummyFragment(12783): onCreate
01-05 23:54:19.968: V/MyFragmentActivity(12783): onFriendAddedAsyncTask/doInBackground
01-05 23:54:19.973: V/DummyFragment(12783): onCreateView
01-05 23:54:19.973: V/DummyFragment(12783): onActivityCreated
01-05 23:54:19.973: V/DummyFragment(12783): onStart
01-05 23:54:19.973: V/DummyFragment(12783): onResume
01-05 23:54:21.933: V/MyFragmentActivity(12783): onSaveInstanceState
01-05 23:54:21.933: V/DummyFragment(12783): onSaveInstanceState
01-05 23:54:21.933: V/MyFragmentActivity(12783): onPause
01-05 23:54:21.933: V/DummyFragment(12783): onPause
01-05 23:54:21.938: V/MyFragmentActivity(12783): onStop
01-05 23:54:21.938: V/DummyFragment(12783): onStop
01-05 23:54:21.938: V/MyFragmentActivity(12783): onDestroy
01-05 23:54:21.938: V/DummyFragment(12783): onDestroyView
01-05 23:54:21.938: V/DummyFragment(12783): onDestroy
01-05 23:54:21.938: V/DummyFragment(12783): onDetach
01-05 23:54:21.978: V/MyFragmentActivity(12783): onCreate
01-05 23:54:21.978: V/DummyFragment(12783): onAttach
01-05 23:54:21.978: V/DummyFragment(12783): onCreate
01-05 23:54:22.263: V/MyFragmentActivity(12783): onStart
01-05 23:54:22.313: V/DummyFragment(12783): onCreateView
01-05 23:54:22.313: V/DummyFragment(12783): onActivityCreated
01-05 23:54:22.313: V/DummyFragment(12783): onStart
01-05 23:54:22.323: V/MyFragmentActivity(12783): onResume
01-05 23:54:22.323: V/MyFragmentActivity(12783): onPostResume
01-05 23:54:22.323: V/MyFragmentActivity(12783): onResumeFragments
01-05 23:54:22.323: V/DummyFragment(12783): onResume
01-05 23:54:27.123: V/MyFragmentActivity(12783): onFriendAddedAsyncTask/onPostExecute
01-05 23:54:27.123: D/AndroidRuntime(12783): Shutting down VM
01-05 23:54:27.123: W/dalvikvm(12783): threadid=1: thread exiting with uncaught exception (group=0x4001d7d0)
01-05 23:54:27.138: E/AndroidRuntime(12783): FATAL EXCEPTION: main
01-05 23:54:27.138: E/AndroidRuntime(12783): Java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.Java:1314)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.Java:1325)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.Java:548)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.support.v4.app.BackStackRecord.commit(BackStackRecord.Java:532)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at com.xyz.dummy.MyFragmentActivity$onFriendAddedAsyncTask.onPostExecute(MyFragmentActivity.Java:447)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at com.xyz.dummy.MyFragmentActivity$onFriendAddedAsyncTask.onPostExecute(MyFragmentActivity.Java:1)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.os.AsyncTask.finish(AsyncTask.Java:417)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.os.AsyncTask.access$300(AsyncTask.Java:127)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.Java:429)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.os.Handler.dispatchMessage(Handler.Java:99)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.os.Looper.loop(Looper.Java:123)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Android.app.ActivityThread.main(ActivityThread.Java:4627)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Java.lang.reflect.Method.invokeNative(Native Method)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at Java.lang.reflect.Method.invoke(Method.Java:521)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:858)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:616)
01-05 23:54:27.138: E/AndroidRuntime(12783):    at dalvik.system.NativeStart.main(Native Method)

Dans d'autres discussions sur des problèmes similaires, la raison semble être que la méthode onPostExecute est appelée avant la méthode onResume (). Mais je reçois l'exception même si onResume () est appelé auparavant.

Est-ce que quelqu'un sait ce qui ne va pas?

L'activité ressemble à ceci:

public class MyFragmentActivity extends FragmentActivity implements OnFriendSelectedListener, OnFriendAddedListener, OnFriendOptionSelectedListener, LoaderCallbacks<Cursor> {

@Override
public void onCreate(Bundle savedInstanceState) {
    Log.v("MyFragmentActivity", "onCreate");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_activity_layout);
    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    FriendListFragment friendListFragment = (FriendListFragment)fm.findFragmentById(R.id.friend_list_fragment_layout);
    if (friendListFragment == null) {
        friendListFragment = new FriendListFragment(); 
        ft.add(R.id.friend_list_fragment_layout, friendListFragment);
        ft.commit();
        fm.executePendingTransactions();
        startService(new Intent(this, MyIntentService.class));
        getSupportLoaderManager().initLoader(CHECK_EMPTY_DATABASE, null, this);
    }
}

    @Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.fragment_activity_options_menu, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    super.onOptionsItemSelected(item);
    switch (item.getItemId()) {
    case R.id.add_friend_menu_item:
        AddFriendDialogFragment addFriendDialogFragment = AddFriendDialogFragment.newInstance();
        addFriendDialogFragment.show(getSupportFragmentManager(), "add_friend_dialog_fragment");
        return true;
    default:
        return false;
    }
}

@Override
public void onFriendAdded(String name) {
    name = name.trim();
    if (name.length() > 0) {
        new onFriendAddedAsyncTask().execute(name);
    }
}

Lorsque j'utilise commitAllowingStateLoss (), j'obtiens l'exception suivante:

01-06 14:54:29.548: E/AndroidRuntime(18020): FATAL EXCEPTION: main
01-06 14:54:29.548: E/AndroidRuntime(18020): Java.lang.IllegalStateException: Activity has been destroyed
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.Java:1329)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.Java:548)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.Java:536)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at com.xyz.dummy.FadiaFragmentActivity$onFriendAddedAsyncTask.onPostExecute(FadiaFragmentActivity.Java:461)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at com.xyz.dummy.FadiaFragmentActivity$onFriendAddedAsyncTask.onPostExecute(FadiaFragmentActivity.Java:1)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.os.AsyncTask.finish(AsyncTask.Java:417)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.os.AsyncTask.access$300(AsyncTask.Java:127)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.Java:429)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.os.Handler.dispatchMessage(Handler.Java:99)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.os.Looper.loop(Looper.Java:123)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Android.app.ActivityThread.main(ActivityThread.Java:4627)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Java.lang.reflect.Method.invokeNative(Native Method)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at Java.lang.reflect.Method.invoke(Method.Java:521)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:858)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:616)
01-06 14:54:29.548: E/AndroidRuntime(18020):    at dalvik.system.NativeStart.main(Native Method)

Je reçois le même IllegalStateExeption lorsque j'implémente AsynTask comme suit, car la méthode findFragmentById () renvoie un pointeur null.

private class onFriendAddedAsyncTask extends AsyncTask<String, Void, String> {

    protected void onPreExecute() {
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute");
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        DummyFragment dummyFragment = DummyFragment.newInstance();
        ft.add(R.id.dummy_fragment_layout, dummyFragment);
        ft.commit();
    }

    protected void onPostExecute(String result) {
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute");
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        DummyFragment dummyFragment = (DummyFragment) fm.findFragmentById(R.id.dummy_fragment_layout);
        ft.remove(dummyFragment);
        ft.commitAllowingStateLoss();
    }

Dans l'étape suivante, j'utilise un gestionnaire pour ajouter et supprimer le DummyFragment. De plus, j'ai ajouté quelques sorties de débogage.

private class onFriendAddedAsyncTask extends AsyncTask<String, Void, String> {

    @Override
    protected void onPreExecute() {
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute " + getSupportFragmentManager());
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute " + getSupportFragmentManager().findFragmentById(R.id.dummy_fragment_layout));
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute " + getSupportFragmentManager().findFragmentById(R.id.friend_list_fragment_layout));

        new Handler().post(new Runnable() {
            public void run() {
                Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute " + getSupportFragmentManager());
                Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute " + getSupportFragmentManager().findFragmentById(R.id.dummy_fragment_layout));
                Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPreExecute " + getSupportFragmentManager().findFragmentById(R.id.friend_list_fragment_layout));
                FragmentManager fm = getSupportFragmentManager();
                FragmentTransaction ft = fm.beginTransaction();
                DummyFragment dummyFragment = DummyFragment.newInstance();
                ft.add(R.id.dummy_fragment_layout, dummyFragment);
                ft.commit();
            }
        });

    @Override
    protected void onPostExecute(String result) {
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute " + getSupportFragmentManager());
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute " + getSupportFragmentManager().findFragmentById(R.id.dummy_fragment_layout));
        Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute " + getSupportFragmentManager().findFragmentById(R.id.friend_list_fragment_layout));

        new Handler().post(new Runnable() {
            public void run() {
                Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute " + getSupportFragmentManager());
                Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute " + getSupportFragmentManager().findFragmentById(R.id.dummy_fragment_layout));
                Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute " + getSupportFragmentManager().findFragmentById(R.id.friend_list_fragment_layout));
                FragmentManager fm = getSupportFragmentManager();
                FragmentTransaction ft = fm.beginTransaction();
                DummyFragment dummyFragment = (DummyFragment) fm.findFragmentById(R.id.dummy_fragment_layout);
                ft.remove(dummyFragment);
                ft.commitAllowingStateLoss();
            }
        });

Je reçois LogCut suivant:

01-07 19:00:17.273: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPreExecute FragmentManager{45e384a8 in MyFragmentActivity{45e38358}}
01-07 19:00:17.273: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPreExecute null
01-07 19:00:17.273: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPreExecute FriendListFragment{45e38ab0 #0 id=0x7f0a0002}
01-07 19:00:17.283: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPreExecute FragmentManager{45e384a8 in MyFragmentActivity{45e38358}}
01-07 19:00:17.288: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/doInBackground
01-07 19:00:17.288: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPreExecute null
01-07 19:00:17.288: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPreExecute FriendListFragment{45e38ab0 #0 id=0x7f0a0002}
01-07 19:00:17.308: V/DummyFragment(4124): onAttach DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:17.308: V/DummyFragment(4124): onCreate DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:17.308: V/DummyFragment(4124): onCreateView DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:17.308: V/DummyFragment(4124): onActivityCreated DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:17.308: V/DummyFragment(4124): onStart DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:17.313: V/DummyFragment(4124): onResume DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.098: V/MyFragmentActivity(4124): onSaveInstanceState DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.098: V/DummyFragment(4124): onSaveInstanceState DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.098: V/MyFragmentActivity(4124): onPause DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.098: V/DummyFragment(4124): onPause DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.103: V/MyFragmentActivity(4124): onStop DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.103: V/DummyFragment(4124): onStop DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.103: V/MyFragmentActivity(4124): onDestroy DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.103: V/DummyFragment(4124): onDestroyView DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.108: V/DummyFragment(4124): onDestroy DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.113: V/DummyFragment(4124): onDetach DummyFragment{45dd7498 #2 id=0x7f0a0004}
01-07 19:00:18.138: V/MyFragmentActivity(4124): onCreate
01-07 19:00:18.138: V/FriendListFragment(4124): FriendListFragment
01-07 19:00:18.138: V/FriendListFragment(4124): onAttach FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.138: V/FriendListFragment(4124): onCreate FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.148: V/DummyFragment(4124): onAttach DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.153: V/DummyFragment(4124): onCreate DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.523: V/MyFragmentActivity(4124): onStart DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.543: V/FriendListFragment(4124): onActivityCreated FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.548: V/DummyFragment(4124): onCreateView DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.548: V/DummyFragment(4124): onActivityCreated DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.548: V/FriendListFragment(4124): onLoadFinished FragmentManager{45d8e478 in MyFragmentActivity{45e4a6d8}}
01-07 19:00:18.548: V/FriendListFragment(4124): onLoadFinished FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.553: V/DummyFragment(4124): onStart DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.553: V/FriendListFragment(4124): onLoadFinished FragmentManager{45d8e478 in MyFragmentActivity{45e4a6d8}}
01-07 19:00:18.553: V/FriendListFragment(4124): onLoadFinished FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.558: V/MyFragmentActivity(4124): onResume DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.558: V/MyFragmentActivity(4124): onPostResume DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.558: V/MyFragmentActivity(4124): onResumeFragments DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.558: V/FriendListFragment(4124): onResume FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.563: V/FriendListFragment(4124): onCreateLoader FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.563: V/DummyFragment(4124): onResume DummyFragment{45d7d1a0 #2 id=0x7f0a0004}
01-07 19:00:18.723: V/FriendListFragment(4124): onLoadFinished FragmentManager{45d8e478 in MyFragmentActivity{45e4a6d8}}
01-07 19:00:18.723: V/FriendListFragment(4124): onLoadFinished FriendListFragment{45e4a7f8 #0 id=0x7f0a0002}
01-07 19:00:18.893: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPostExecute FragmentManager{45e384a8 in null}}
01-07 19:00:18.893: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPostExecute null
01-07 19:00:18.893: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPostExecute null
01-07 19:00:18.923: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPostExecute FragmentManager{45e384a8 in null}}
01-07 19:00:18.923: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPostExecute null
01-07 19:00:18.923: V/MyFragmentActivity(4124): onFriendAddedAsyncTask/onPostExecute null
01-07 19:00:18.928: D/AndroidRuntime(4124): Shutting down VM
01-07 19:00:18.928: W/dalvikvm(4124): threadid=1: thread exiting with uncaught exception (group=0x4001d7d0)
01-07 19:00:18.938: E/AndroidRuntime(4124): FATAL EXCEPTION: main
01-07 19:00:18.938: E/AndroidRuntime(4124): Java.lang.IllegalStateException: Activity has been destroyed
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.Java:1329)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.Java:548)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.Java:536)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at com.xyz.dummy.MyFragmentActivity$onFriendAddedAsyncTask$2.run(MyFragmentActivity.Java:476)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Android.os.Handler.handleCallback(Handler.Java:587)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Android.os.Handler.dispatchMessage(Handler.Java:92)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Android.os.Looper.loop(Looper.Java:123)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Android.app.ActivityThread.main(ActivityThread.Java:4627)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Java.lang.reflect.Method.invokeNative(Native Method)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at Java.lang.reflect.Method.invoke(Method.Java:521)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:858)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:616)
01-07 19:00:18.938: E/AndroidRuntime(4124):     at dalvik.system.NativeStart.main(Native Method)

Dans onPreExecute (), FriendListFragment a l'id = 0x7f0a0002. Dans le gestionnaire, le DummyFragment est créé avec id = 0x7f0a0004. Dans onPostExecute (), les deux ID sont null . Dans onPreExecute (), l'adresse de MyFragmentActivity est 45e38358. mais dans onPostExecute () c'est null. Mais dans les deux méthodes, l'adresse FragmentManager est 45e384a8 . Je suppose que onPostExecute utilise un FragmentManager non valide. Mais pourquoi?

130
samo

Vous devriez faire la transaction dans une Handler comme suit:

@Override
protected void onPostExecute(String result) {
    Log.v("MyFragmentActivity", "onFriendAddedAsyncTask/onPostExecute");
    new Handler().post(new Runnable() {
            public void run() {
                fm = getSupportFragmentManager();
                ft = fm.beginTransaction();
                ft.remove(dummyFragment);
                ft.commit();
            }
        });
}
95
Oleg Vaskevich

Merci Oleg Vaskevich. L'utilisation d'une WeakReference de la FragmentActivity a résolu le problème. Mon code ressemble maintenant à ceci:

public class MyFragmentActivity extends FragmentActivity implements OnFriendAddedListener {

    private static WeakReference<MyFragmentActivity> wrActivity = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        wrActivity = new WeakReference<MyFragmentActivity>(this);
        ...

    private class onFriendAddedAsyncTask extends AsyncTask<String, Void, String> {

        @Override
        protected void onPreExecute() {
            FragmentManager fm = getSupportFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            DummyFragment dummyFragment = DummyFragment.newInstance();
            ft.add(R.id.dummy_fragment_layout, dummyFragment);
            ft.commit();
        }

        @Override
        protected void onPostExecute(String result) {
            final Activity activity = wrActivity.get();
            if (activity != null && !activity.isFinishing()) {
                FragmentManager fm = activity.getSupportFragmentManager();
                FragmentTransaction ft = fm.beginTransaction();
                DummyFragment dummyFragment = (DummyFragment) fm.findFragmentById(R.id.dummy_fragment_layout);
                ft.remove(dummyFragment);
                ft.commitAllowingStateLoss();
            }
        }
53
samo

Je crois que la bonne réponse à cette question est la méthode suivante.

public abstract int commitAllowingStateLoss ()

Comme commit () mais permet l'exécution de la validation après le .__ d'une activité. l'état est enregistré. Ceci est dangereux car le commit peut être perdu si l'activité doit être restaurée ultérieurement à partir de son état initial. être utilisé uniquement dans les cas où il est acceptable que l'état de l'interface utilisateur change de manière inattendue sur l'utilisateur.

La description ci-dessus concerne cette méthode.

protected void onSaveInstanceState(Android.os.Bundle outState)

Ce problème se produit précisément lorsque l'appareil se met en veille.

http://developer.Android.com/reference/Android/app/FragmentTransaction.html

35
alex

Solution courte et efficace:

Suivez les étapes simples:

Étape 1 : Remplacez l'état onSaveInstanceState dans le fragment respectif. Et enlevez la super méthode.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Étape 2 : Utilisez CommitAllowingStateLoss(); au lieu de commit(); pendant les opérations de fragment.

fragmentTransaction.commitAllowingStateLoss();
24
Basbous

Vérifiez si l'activité isFinishing() avant d'afficher le fragment.

Exemple:

if(!isFinishing()) {
FragmentManager fm = getSupportFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            DummyFragment dummyFragment = DummyFragment.newInstance();
            ft.add(R.id.dummy_fragment_layout, dummyFragment);
            ft.commitAllowingStateLoss();
}
10
Naskov

J'ai eu un problème similaire que j'ai résolu en déplaçant un code de transaction de fragment de onResume() dans onStart().

Pour être plus précis: mon application est un lanceur. Après avoir appuyé sur le bouton d'accueil Android, l'utilisateur peut choisir un lanceur jusqu'à ce que sa décision soit mémorisée. Lors du retour "en arrière" à ce stade (par exemple en tapotant dans la zone grisâtre), l'application s'est bloquée.

Peut-être que cela aide quelqu'un.

5
Alex

Il existe une solution alternative (PAS la meilleure solution) à ce problème, mais qui fonctionne. En utilisant flag, vous pouvez le gérer, comme ci-dessous

/**
 * Flag to avoid "Java.lang.IllegalStateException: Can not perform this action after
 * onSaveInstanceState". Avoid Fragment transaction until onRestoreInstanceState or onResume
 * gets called.
 */
private boolean isOnSaveInstanceStateCalled = false;


@Override
public void onRestoreInstanceState(final Bundle bundle) {
    .....
    isOnSaveInstanceStateCalled = false;
    .....
}

@Override
public void onSaveInstanceState(final Bundle outState) {
    .....
    isOnSaveInstanceStateCalled = true;
    .....
}

@Override
public void onResume() {
    super.onResume();
    isOnSaveInstanceStateCalled = false;
    .....
}

Et vous pouvez vérifier cette valeur boolean en effectuant une transaction fragmentée.

private void fragmentReplace(Fragment fragment, String fragmentTag){
    if (!isOnSaveInstanceStateCalled) {
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.layout_container, fragment, fragmentTag)
                .commit();
    }
}
2
Pankaj Kumar

Cela m'est arrivé parce que j'appelais commit() du sous-fragment qui présentait une fuite d'activité. Elle conservait l'activité en tant que propriété et la variable d'activité de rotation n'était pas mise à jour par onAttach();. J'essayais donc de valider une transaction sur une activité zombie en conservant le fragment (setRetainInstance(true);).

2
Malachiasz

Utilisez commitAllowingStateLoss() au lieu de commit().

lorsque vous utilisez commit(), une exception peut être levée en cas de perte d'état, mais commitAllowingStateLoss() enregistre la transaction sans perte d'état, de sorte qu'elle ne lève pas d'exception en cas de perte d'état.

2
felhi

La raison de cette exception est la recréation de FragmentActivity pendant l'exécution de AsyncTask et l'accès à la précédente FragmentActivity détruite dans onPostExecute() après.

Le problème est d’obtenir une référence valide à la nouvelle FragmentActivity. Il n'y a pas de méthode pour cela ni getActivity(), ni findById() ou quelque chose de similaire. Ce forum est rempli de discussions en fonction de ce problème (par exemple, recherche de "Activity context in onPostExecute"). Certains d'entre eux décrivent des solutions de contournement (jusqu'à présent, je n'en trouvais pas une bonne).

Ce serait peut-être une meilleure solution d’utiliser un service à mes fins.

2
samo

Solution 1: Annulez onSaveInstanceState() et supprimez le super appel qui s'y trouve.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Solution 2: Remplacez onSaveInstanceState() et supprimez votre fragment avant le super appel

@Override
public void onSaveInstanceState(Bundle outState) {
     // TODO: Add code to remove fragment here
     super.onSaveInstanceState(outState);
}
1
Lingkun Kong

Pour ce que ça vaut J'ai eu cette erreur sur une application qui exécutait des services en arrière-plan. Sur l'un d'eux, une boîte de dialogue de délai d'attente devait être affichée à l'utilisateur. Cette boîte de dialogue était le problème à l'origine de cette erreur si l'application ne fonctionnait plus au premier plan.

Dans notre cas, montrer que la boîte de dialogue n'était pas utile lorsque l'application était en arrière-plan, nous avons donc gardé une trace de cela (le booléen signalé parPause en onResume) et ensuite n'afficher la boîte de dialogue que lorsque l'application est réellement visible pour l'utilisateur.

1
hcpl

Ce problème se produit lorsqu'un processus tente de manipuler une activité dont la fonction onStop() a été appelée. Ce n'est pas nécessairement lié à une transaction de fragment, mais aussi à d'autres méthodes comme onBackPressed ().

En plus de AsyncTask, une autre source de ce problème est le mauvais placement de l'abonnement du modèle de bus. L'abonnement Event Bus ou RxBus est généralement enregistré lors de l'activité onCreate de l'activité et désenregistré dans onDestroy. Si une nouvelle activité démarre et publie un événement intercepté par des abonnés de l'activité précédente, une erreur risque alors de se produire. Si cela se produit, une solution consiste à déplacer l'enregistrement de l'abonnement et le désenregistrement vers onStart() et onStop()

1
inmyth

À partir de la version 24.0.0 de la bibliothèque de support, vous pouvez appeler la méthode FragmentTransaction.commitNow() qui valide cette transaction de manière synchrone au lieu d'appeler commit() suivi de executePendingTransactions().

0

IllegalStateException est rencontré si vous validez une transaction de fragment après que l’activité a perdu son état. L’activité n’est pas au premier plan. Cela se produit généralement lorsque vous essayez de valider un fragment en AsyncTask ou après une requête réseau. 

Pour éviter ce blocage, il vous suffit de retarder toute transaction de fragment jusqu'à ce que l'état de l'activité soit restauré. Voici comment cela se fait

Déclarer deux variables booléennes privées

public class MainActivity extends AppCompatActivity {

    //Boolean variable to mark if the transaction is safe
    private boolean isTransactionSafe;

    //Boolean variable to mark if there is any transaction pending
    private boolean isTransactionPending;

Maintenant, dans onPostResume () et onPause, nous définissons et désactivons notre variable booléenne isTransactionSafe. L'idée est de marquer la sécurité de la transaction uniquement lorsque l'activité est au premier plan afin d'éviter toute possibilité de perte de mémoire.

/*
onPostResume is called only when the activity's state is completely restored. In this we will
set our boolean variable to true. Indicating that transaction is safe now
 */
public void onPostResume(){
    super.onPostResume();
    isTransactionSafe=true;
}
/*
onPause is called just before the activity moves to background and also before onSaveInstanceState. In this
we will mark the transaction as unsafe
 */

public void onPause(){
    super.onPause();
    isTransactionSafe=false;

}

private void commitFragment(){
    if(isTransactionSafe) {
        MyFragment myFragment = new MyFragment();
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.frame, myFragment);
        fragmentTransaction.commit();
    }
}

Ce que nous avons fait jusqu’à présent épargnera IllegalStateException, mais nos transactions seront perdues si elles sont effectuées une fois l’activité passée à l’arrière-plan, un peu comme commitAllowStateloss (). Pour aider avec cela, nous avons la variable booléenne isTransactionPending

public void onPostResume(){
   super.onPostResume();
   isTransactionSafe=true;
/* Here after the activity is restored we check if there is any transaction pending from
the last restoration
*/
   if (isTransactionPending) {
      commitFragment();
   }
}


private void commitFragment(){

 if(isTransactionSafe) {
     MyFragment myFragment = new MyFragment();
     FragmentManager fragmentManager = getFragmentManager();
     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
     fragmentTransaction.add(R.id.frame, myFragment);
     fragmentTransaction.commit();
     isTransactionPending=false;
 }else {
     /*
     If any transaction is not done because the activity is in background. We set the
     isTransactionPending variable to true so that we can pick this up when we come back to
foreground
     */
     isTransactionPending=true;
 }
}

Cet article explique assez en détail pourquoi cette exception est rencontrée et compare différentes méthodes pour la résoudre. Hautement recommandé

0
IrshadKumail

Mon application a un fragment à charger en 3 secondes, mais lorsque l'écran de poing se prépare à afficher, j'appuie sur le bouton d'accueil et le relance, il affiche la même erreur.

new Handler().post(new Runnable() {
        public void run() {
            if (saveIns == null) {
                mFragment = new Fragment_S1_loading();
                getFragmentManager().beginTransaction()
                        .replace(R.id.container, mFragment).commit();
            }
            getActionBar().hide();
            // Loading screen in 3 secs:
            mCountDownTimerLoading = new CountDownTimer(3000, 1000) {

                @Override
                public void onTick(long millisUntilFinished) {

                }

                @Override
                public void onFinish() {
                    if (saveIns == null) {// TODO bug when start app and press home
                                            // button
                        getFragmentManager()
                                .beginTransaction()
                                .replace(R.id.container,
                                        new Fragment_S2_sesstion1()).commitAllowingStateLoss();
                    }
                    getActionBar().show();
                }
            }.start();
        }
    });

NOTE: add commitAllowingStateLoss () au lieu de commit ()

0
nobjta_9x_tq

J'ai eu la même exception et j'ai essayé de nombreux extraits que j'ai trouvés ici sur cette discussion de stackoverflow, mais aucun extrait n'a fonctionné pour moi. 

Mais j'ai réussi à résoudre tous les problèmes, je partagerai avec vous les solutions:

  • Dans une première partie: j'ai essayé d'afficher un DialogFragment sur une activité mais à partir d'une autre classe Java. Ensuite, en vérifiant l'attribut de cette instance, j'ai découvert qu'il s'agissait d'une ancienne instance de Activity et non de l'activité en cours. [Plus précisément, j’utilisais socket.io et j’avais oublié de faire un socket.off ("exemple", exemple) ... il était donc attaché à une ancienne instance de l’activité. ]

  • Deuxième partie: J'essayais de montrer un DialogFragment dans une activité lorsque j'y revenais avec une intention, mais lorsque j'ai consulté mes journaux, j'ai constaté que, lorsqu'il essayait de montrer le fragment, l'activité n'était toujours pas dans la méthode onStart , elle a donc planté l’application car elle n’a pas trouvé la classe d’activité pour afficher le fragment dessus. 

Quelques conseils: vérifiez avec certains attributs si vous n'utilisez pas une ancienne instance de votre activité avec laquelle vous essayez de montrer votre fragment, ou vérifiez votre cycle de vie d'activité avant de montrer votre fragment et assurez-vous d'être bien dans onStart ou onResume avant de le montrer. . 

J'espère que ces explications vous aideront. 

0
Raj