java.lang.IllegalStateException: Diese Aktion kann nach onSaveInstanceState nicht ausgeführt werden

135

Ich verwende die Support-Bibliothek für meine App. In meiner FragmentActivity verwende ich eine AsyncTask zum Herunterladen von Daten aus dem Internet. In der onPreExecute () -Methode füge ich ein Fragment hinzu und in der onPostExecute () -Methode entferne ich es erneut. Wenn die Ausrichtung dazwischen geändert wird, erhalte ich die oben genannte Ausnahme. Bitte schauen Sie sich die Details an:

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");
    ...
}

Ich erhalte folgenden LogCut:

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)

In anderen Threads zu ähnlichen Problemen scheint der Grund darin zu liegen, dass die onPostExecute-Methode aufgerufen wird, bevor die onResume () -Methode aufgerufen wird. Aber ich bekomme die Ausnahme, obwohl onResume () vorher aufgerufen wurde.

Weiß jemand, was los ist?

Die Aktivität sieht folgendermaßen aus:

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);
    }
}

Bei Verwendung von commitAllowingStateLoss () tritt folgende Ausnahme auf:

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)

Ich erhalte dieselbe IllegalStateExeption, wenn ich die AsynTask wie folgt implementiere, da die findFragmentById () -Methode einen Nullzeiger zurückgibt.

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();
    }

Im nächsten Schritt verwende ich einen Handler zum Hinzufügen und Entfernen des DummyFragments. Zusätzlich habe ich einige weitere Debug-Ausgaben hinzugefügt.

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();
            }
        });

Ich erhalte folgenden LogCut:

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)

In onPreExecute () hat das FriendListFragment die ID = 0x7f0a0002. Im Handler wird das DummyFragment mit der ID = 0x7f0a0004 erstellt. In onPostExecute () sind beide IDs null. In onPreExecute () lautet die Adresse von MyFragmentActivity 45e38358. aber in onPostExecute () ist es null. Bei beiden Methoden lautet die FragmentManager-Adresse jedoch 45e384a8. Ich denke, onPostExecute verwendet einen ungültigen FragmentManager. Aber wieso?

Samo
quelle
1
Ich hatte dieses Problem einmal und habe es behoben, indem ich das Commit durch das folgende ersetzt habe: commitAllowingStateLoss (), können Sie dies versuchen?
Cata
Ich habe es bereits versucht, aber ohne Erfolg. Laut LogCat sollte sich das Fragment im richtigen Zustand befinden.
Samo
Können Sie bitte Ihren Aktivitätscode posten?
Robert Estivill
Wenn ich commitAllowingStateLoss () verwende, erhalte ich eine andere Ausnahme (siehe oben).
samo
6
Für diejenigen unter Ihnen, die noch nach einer Lösung suchen ... Weitere Informationen finden Sie in diesem Blogbeitrag zu diesem Thema.
Alex Lockwood

Antworten:

97

Sie sollten die Transaktion Handlerwie folgt ausführen:

@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();
            }
        });
}
Oleg Vaskevich
quelle
12
Es hilft nicht. Das Verhalten ist das gleiche wie zuvor.
Samo
@samo bitte konnten Sie das Problem lösen? Ich habe eine sehr ähnliche Situation Link
Lisa Anne
3
Betrachten Sie diesen Code:private static WeakReference<FragmentActivity> mActivity = null;
Oleg Vaskevich
2
Kurz gesagt, WeakReferenceverhindert, dass Sie die Aktivität verlieren ... Sie müssen aufrufen mActivity.get(), um die Instanz tatsächlich zu erhalten, und sie ist null, wenn die Aktivität zerstört wurde. Um es zu aktualisieren, müssen Sie schreiben mActivity = new WeakReference<FragmentActivity>(this);- ein guter Ort ist in onCreate()-, der die Referenz aktualisiert.
Oleg Vaskevich
107
Für diejenigen unter Ihnen, die noch nach einer Lösung suchen ... Weitere Informationen finden Sie in diesem Blogbeitrag zu diesem Thema.
Alex Lockwood
55

Danke Oleg Vaskevich. Mit einem WeakReferenceder FragmentActivitydas Problem gelöst. Mein Code sieht jetzt wie folgt aus:

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();
            }
        }
Samo
quelle
Die schwache Referenzidee ist in der Tat sehr klug. Dies würde es dem Objekt ermöglichen, bei Bedarf leicht Müll zu sammeln. Daumen hoch Samo!
Jimmy Ilenloa
Warum wird hier statisch verwendet? Was passiert , wenn ich MyFragmentActivity mActivity = this ?mit aus statischem & WeakReference
Bharat
Statische Referenz ist ziemlich schlechte Technik, Sie sollten lieber Ihre Asynchtask an den Lebenszyklus binden und abbrechen, wenn es nötig ist
Bruchlinie
38

Ich glaube, die richtige Antwort auf diese Frage ist die folgende Methode.

public abstract int commitAllowingStateLoss ()

Wie commit (), ermöglicht jedoch die Ausführung des Commits, nachdem der Status einer Aktivität gespeichert wurde. Dies ist gefährlich, da das Festschreiben verloren gehen kann, wenn die Aktivität später aus ihrem Status wiederhergestellt werden muss. Dies sollte daher nur in Fällen verwendet werden, in denen es in Ordnung ist, dass sich der UI-Status für den Benutzer unerwartet ändert.

Die obige Beschreibung bezieht sich auf dieses Verfahren.

protected void onSaveInstanceState(android.os.Bundle outState)

Dieses Problem tritt genau dann auf, wenn das Gerät in den Ruhezustand wechselt.

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

Alex
quelle
25

Kurze und funktionierende Lösung:

Befolgen Sie einfache Schritte:

Schritt 1 : Überschreiben Sie den onSaveInstanceStateStatus im jeweiligen Fragment. Und entfernen Sie die Super-Methode daraus.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Schritt 2 : Verwenden Sie CommitAllowingStateLoss();anstelle von commit();while-Fragmentoperationen.

fragmentTransaction.commitAllowingStateLoss();
Basbous
quelle
2
Vielen Dank. Das funktioniert bei mir, aber ich weiß, dass das nicht die beste Lösung ist.
Wendigo
2
Durch das Entfernen der Supermethode wird auch das Speichern Ihrer Fragmentzustände deaktiviert.
Juan Mendez
1
Vielen Dank. Es wurde eine Ausnahme generiert. Diese Lösung hat gut funktioniert.
Deepak
11

Überprüfen Sie die Aktivität, isFinishing()bevor Sie das Fragment anzeigen.

Beispiel:

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

Ich hatte ein ähnliches Problem, das ich behoben habe, indem ich einen Fragmenttransaktionscode von onResume()in verschoben habe onStart().

Genauer gesagt: Meine App ist ein Launcher. Nach dem Drücken der Android Home-Taste kann der Benutzer einen Launcher auswählen, bis seine Entscheidung gespeichert ist. Wenn Sie an dieser Stelle "zurück" gehen (z. B. durch Tippen auf den grauen Bereich), stürzte die App ab.

Vielleicht hilft das jemandem.

Alex
quelle
4

Verwenden Sie commitAllowingStateLoss()anstelle von commit().

Wenn Sie commit()es verwenden, kann es eine Ausnahme auslösen, wenn ein Statusverlust auftritt, aber eine commitAllowingStateLoss()Transaktion ohne Statusverlust speichern, sodass keine Ausnahme ausgelöst wird, wenn ein Statusverlust auftritt.

felhi
quelle
2

Das passierte für mich, weil ich mich auf ein commit()Subfragment berief, das eine undichte Aktivität aufwies. Die Aktivität wurde als Eigenschaft beibehalten, und eine Rotationsaktivitätsvariable wurde von nicht aktualisiert. onAttach();Daher habe ich versucht, eine Transaktion für die Zombie-Aktivität durch ein beibehaltenes (setRetainInstance(true);)Fragment festzuschreiben.

Malachiasz
quelle
2

Der Grund für die Ausnahme ist die Neuschöpfung der FragmentActivitywährend der Laufzeit des AsyncTaskund der Zugriff auf die vorherigen, zerstört FragmentActivityin onPostExecute()danach.

Das Problem besteht darin, einen gültigen Verweis auf das Neue zu erhalten FragmentActivity. Es gibt weder dafür getActivity()noch für findById()etwas Ähnliches eine Methode . Dieses Forum ist voll von Threads zu diesem Thema (zB Suche nach "Activity context in onPostExecute"). Einige von ihnen beschreiben Problemumgehungen (bis jetzt habe ich keine gute gefunden).

Vielleicht wäre es eine bessere Lösung, einen Dienst für meinen Zweck zu nutzen.

Samo
quelle
2

Es gibt eine alternative Lösung (NICHT die beste Lösung) für dieses Problem, die jedoch funktioniert. Mit flag können Sie damit umgehen, wie unten

/**
 * 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;
    .....
}

Und Sie können diesen booleanWert überprüfen , während Sie eine Fragmenttransaktion durchführen.

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

Für das, was es wert ist; Ich hatte diesen Fehler bei einer App, auf der Dienste im Hintergrund ausgeführt wurden. Auf einem von ihnen musste dem Benutzer ein Timeout-Dialog angezeigt werden. Dieser Dialog war das Problem, das diesen Fehler verursachte, wenn die App nicht mehr im Vordergrund lief.

In unserem Fall war das Anzeigen des Dialogfelds nicht hilfreich, wenn sich die App im Hintergrund befand. Wir haben dies nur verfolgt (boolesches Kennzeichen onPause en onResume) und das Dialogfeld dann nur angezeigt, wenn die App für den Benutzer tatsächlich sichtbar ist.

hcpl
quelle
1

Lösung 1: Überschreiben onSaveInstanceState()und entfernen Sie den darin enthaltenen Superanruf.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Lösung 2: Überschreiben onSaveInstanceState()und entfernen Sie Ihr Fragment vor dem Superaufruf

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

Dieses Problem tritt auf, wenn ein Prozess versucht, eine Aktivität zu manipulieren, deren onStop() aufgerufene . Es ist nicht unbedingt an Fragmenttransaktionen gebunden, sondern auch an andere Methoden wie onBackPressed ().

Neben AsyncTask ist eine weitere Ursache für ein solches Problem die Fehlplatzierung des Abonnements des Busmusters. Normalerweise wird das Abonnement von Event Bus oder RxBus während onCreate von Activity registriert und in onDestroy abgemeldet. Wenn eine neue Aktivität ein Ereignis startet und veröffentlicht, das von Abonnenten der vorherigen Aktivität abgefangen wurde, kann dies zu diesem Fehler führen. In diesem Fall besteht eine Lösung darin, die Abonnementregistrierung und -abmeldung nach onStart()und zu verschieben onStop().

inmyth
quelle
1

Dies löste mein Problem: Kotlin Code:

val fragmentTransaction = activity.supportFragmentManager.beginTransaction()
fragmentTransaction.add(dialogFragment, tag)
fragmentTransaction.commitAllowingStateLoss()

Wie commitAllowingStateLoss()ist anders als commit()?

Gemäß Dokumentation:

Wie, commit()aber ermöglicht das Ausführen des Commits, nachdem der Status einer Aktivität gespeichert wurde. https://developer.android.com/reference/android/app/FragmentTransaction#commitAllowingStateLoss ()

PS: Mit dieser Methode können Sie Fragmentdialoge anzeigen oder Fragmente laden. Gilt für beide.

Wajid Ali
quelle
0

Meine App hat ein Fragment, das in 3 Sekunden geladen werden muss. Wenn sich der erste Bildschirm auf die Anzeige vorbereitet, drücke ich die Home-Taste und setze die Ausführung fort. Es wird der gleiche Fehler angezeigt. Daher wird mein Code bearbeitet und es läuft sehr reibungslos:

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();
        }
    });

HINWEIS: Fügen Sie commitAllowingStateLoss () anstelle von commit () hinzu.

nobjta_9x_tq
quelle
0

Ab der Support Library-Version 24.0.0 können Sie eine FragmentTransaction.commitNow()Methode aufrufen , die diese Transaktion synchron festschreibt, anstatt sie aufzurufen, commit()gefolgt vonexecutePendingTransactions()

Volodymyr
quelle
0

IllegalStateException tritt auf, wenn Sie eine Fragmenttransaktion festschreiben, nachdem die Aktivität ihren Status verloren hat. Die Aktivität steht nicht im Vordergrund. Dies tritt häufig auf, wenn Sie versuchen, ein Fragment in AsyncTask oder nach einer Netzwerkanforderung festzuschreiben.

Um diesen Absturz zu vermeiden, müssen Sie lediglich alle Fragmenttransaktionen verzögern, bis der Aktivitätsstatus wiederhergestellt ist. Das Folgende ist, wie es gemacht wird

Deklarieren Sie zwei private boolesche Variablen

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;

Jetzt setzen und deaktivieren wir in onPostResume () und onPause unsere boolesche Variable isTransactionSafe. Die Idee ist, die Transaktion nur dann als sicher zu markieren, wenn die Aktivität im Vordergrund steht, sodass keine Gefahr eines Statusverlusts besteht.

/*
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();
    }
}

Was wir bisher getan haben, wird vor IllegalStateException gespeichert, aber unsere Transaktionen gehen verloren, wenn sie ausgeführt werden, nachdem die Aktivität in den Hintergrund verschoben wurde, ähnlich wie commitAllowStateloss (). Um dies zu unterstützen, haben wir die boolesche Variable 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;
 }
}

In diesem Artikel wird ausführlich erläutert, warum diese Ausnahme auftritt, und es werden verschiedene Methoden zum Beheben dieser Ausnahme verglichen. Sehr empfehlenswert

IrshadKumail
quelle
0

Ich hatte die gleiche Ausnahme und habe viele Snippets ausprobiert, die ich hier in dieser Stackoverflow-Diskussion gefunden habe, aber für mich haben keine Snippets funktioniert.

Aber ich konnte alle Probleme lösen, ich werde Ihnen die Lösungen mitteilen:

  • In einem ersten Teil: Ich habe versucht, ein DialogFragment für eine Aktivität anzuzeigen, aber von einer anderen Java-Klasse. Durch Überprüfen des Attributs dieser Instanz stellte ich fest, dass es sich um eine alte Instanz der Aktivität handelte und nicht um die aktuell ausgeführte Aktivität. [Genauer gesagt habe ich socket.io verwendet und vergessen, ein socket.off ("Beispiel", Beispiel) auszuführen ... also wurde es an eine alte Instanz der Aktivität angehängt. ]]

  • In einem zweiten Teil: Ich habe versucht, ein DialogFragment in einer Aktivität anzuzeigen, als ich mit Absicht darauf zurückkam. Als ich jedoch meine Protokolle überprüfte, stellte ich fest, dass sich die Aktivität beim Versuch, das Fragment anzuzeigen, immer noch nicht in der onStart-Methode befand Daher stürzte die App ab, weil die Aktivitätsklasse zum Anzeigen des Fragments nicht gefunden wurde.

Einige Tipps: Überprüfen Sie anhand einiger Attribute, ob Sie keine alte Instanz Ihrer Aktivität verwenden, mit der Sie Ihr Fragment anzeigen möchten, oder überprüfen Sie Ihren Aktivitätslebenszyklus, bevor Sie Ihr Fragment anzeigen, und stellen Sie sicher, dass Sie sich in onStart oder onResume befinden, bevor Sie es anzeigen .

Ich hoffe, diese Erklärungen werden Ihnen helfen.

Raj
quelle