java.lang.IllegalStateException: nie można wykonać tej czynności po onSaveInstanceState

135

Korzystam z biblioteki pomocy technicznej dla mojej aplikacji. W mojej FragmentActivity używam AsyncTask do pobierania danych z Internetu. W metodzie onPreExecute () dodaję Fragment, aw metodzie onPostExecute () ponownie go usuwam. Kiedy w międzyczasie zmienia się orientacja, pojawia się wspomniany powyżej wyjątek. Proszę spojrzeć na szczegóły:

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

Otrzymuję następujący 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)

W innych wątkach dotyczących podobnych problemów przyczyną wydaje się być to, że metoda onPostExecute jest wywoływana przed wywołaniem metody onResume (). Ale pojawia się wyjątek, mimo że onResume () jest wcześniej wywoływany.

Czy ktoś wie, co się stało?

Działanie wygląda następująco:

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

Podczas korzystania z commitAllowingStateLoss () otrzymuję następujący wyjątek:

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)

Otrzymuję ten sam IllegalStateExeption po zaimplementowaniu AsynTask w następujący sposób, ponieważ metoda findFragmentById () zwraca wskaźnik o wartości 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();
    }

W następnym kroku używam handlera do dodawania i usuwania DummyFragment. Dodatkowo dodałem więcej wyników debugowania.

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

Otrzymuję następujący 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)

W onPreExecute () FriendListFragment ma id = 0x7f0a0002. Wewnątrz procedury obsługi tworzony jest DummyFragment z id = 0x7f0a0004. W onPostExecute () oba identyfikatory mają wartość null. W onPreExecute () adres MyFragmentActivity to 45e38358. ale w onPostExecute () ma wartość null. Ale w obu metodach adres FragmentManager to 45e384a8. Myślę, że onPostExecute używa nieprawidłowego FragmentManager. Ale dlaczego?

samo
źródło
1
Miałem raz ten problem i naprawiłem go, zastępując zatwierdzenie tym: commitAllowingStateLoss (), czy możesz spróbować?
Cata,
Próbowałem już tego, ale bez powodzenia. Zgodnie z LogCat fragment powinien być w odpowiednim stanie.
samo
Czy możesz opublikować swój kod aktywności?
Robert Estivill,
Kiedy używam commitAllowingStateLoss (), pojawia się inny wyjątek (patrz wyżej).
samo
6
Dla tych z Was, którzy wciąż szukają rozwiązania ... zobacz ten wpis na blogu dotyczący tego tematu, aby uzyskać więcej informacji.
Alex Lockwood,

Odpowiedzi:

97

Transakcję należy wykonać w Handlernastępujący sposób:

@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
źródło
12
To nie pomaga. Zachowanie jest takie samo jak wcześniej.
samo
@samo, czy udało Ci się rozwiązać problem? Mam link
Lisa Anne
3
Rozważ ten kod:private static WeakReference<FragmentActivity> mActivity = null;
Oleg Vaskevich
2
Krótko mówiąc, WeakReferencezapobiega wyciekaniu aktywności ... musisz zadzwonić, mActivity.get()aby faktycznie pobrać instancję, i będzie ona zerowa, jeśli aktywność została zniszczona. Aby go zaktualizować, musisz napisać mActivity = new WeakReference<FragmentActivity>(this);- dobre miejsce jest onCreate()- co zaktualizuje odniesienie.
Oleg Vaskevich
107
Dla tych z Was, którzy wciąż szukają rozwiązania ... zobacz ten wpis na blogu dotyczący tego tematu, aby uzyskać więcej informacji.
Alex Lockwood,
55

Dzięki Oleg Vaskevich. Użycie a WeakReferencez FragmentActivityrozwiązanych problemu. Mój kod wygląda teraz następująco:

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
źródło
słaba idea odniesienia jest rzeczywiście bardzo sprytna, co pozwoliłoby na łatwe zbieranie śmieci w razie potrzeby. kciuki w górę samo!
Jimmy Ilenloa
Dlaczego używa się tutaj statycznego? Co jeśli MyFragmentActivity mActivity = this ?
użyję
Statyczny odniesienia jest całkiem zła technika, należy raczej wiązać swoją asynchtask z cyklem i odwołać, gdy jego potrzeby
linią podziału
38

Uważam, że poprawną odpowiedzią na to pytanie jest następująca metoda.

public abstract int commitAllowingStateLoss ()

Podobnie jak commit (), ale umożliwia wykonanie zatwierdzenia po zapisaniu stanu działania. Jest to niebezpieczne, ponieważ zatwierdzenie może zostać utracone, jeśli aktywność będzie później musiała zostać przywrócona ze stanu, więc powinno to być używane tylko w przypadkach, w których stan interfejsu użytkownika może nieoczekiwanie zmienić się na użytkownika.

Powyższy opis dotyczy tej metody.

protected void onSaveInstanceState(android.os.Bundle outState)

Ten problem występuje właśnie wtedy, gdy urządzenie zasypia.

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

Alex
źródło
25

Krótkie i działające rozwiązanie:

Wykonaj proste kroki:

Krok 1 : Zastąp onSaveInstanceStatestan w odpowiednim fragmencie. I usuń z tego super metodę.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Krok 2 : Użyj CommitAllowingStateLoss();zamiast commit();while operacji na fragmentach.

fragmentTransaction.commitAllowingStateLoss();
Basbous
źródło
2
Dzięki. U mnie to działa, ale wiem, że to nie jest najlepsze rozwiązanie.
wendigo
2
usunięcie super metody, wyłącza również zapisywanie stanów fragmentów.
Juan Mendez
1
Wielkie dzięki. Generował wyjątek, to rozwiązanie działało dobrze ..
Deepak,
11

Sprawdź, czy aktywność isFinishing()przed pokazaniem fragmentu.

Przykład:

if(!isFinishing()) {
FragmentManager fm = getSupportFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            DummyFragment dummyFragment = DummyFragment.newInstance();
            ft.add(R.id.dummy_fragment_layout, dummyFragment);
            ft.commitAllowingStateLoss();
}
Naskov
źródło
5

Miałem podobny problem, który naprawiłem, przenosząc fragment kodu transakcji z onResume()do onStart().

Mówiąc dokładniej: moja aplikacja to program uruchamiający. Po naciśnięciu przycisku Android Home użytkownik może wybrać program uruchamiający do momentu zapamiętania jego decyzji. Podczas przechodzenia „wstecz” w tym momencie (np. Dotykając szarego obszaru) aplikacja uległa awarii.

Może to komuś pomoże.

Alex
źródło
4

Użyj commitAllowingStateLoss()zamiast commit().

kiedy commit()go użyjesz , może zgłosić wyjątek, jeśli wystąpi utrata stanu, ale commitAllowingStateLoss()zapisuje transakcję bez utraty stanu, aby nie zgłosił wyjątku, jeśli wystąpi utrata stanu.

felhi
źródło
2

Stało się to dla mnie, ponieważ wywoływałem commit()z subfragmentu, który przeciekał. Zachował aktywność jako właściwość, a zmienna dotycząca aktywności rotacji nie została zaktualizowana przez onAttach();Więc próbowałem zatwierdzić transakcję na Aktywność zombie przez zachowany (setRetainInstance(true);)fragment.

Malachiasz
źródło
2

Powodem wyjątkiem jest ponowne utworzenie FragmentActivitypodczas runtime AsyncTaskoraz dostępu do poprzedniego, zniszczonego FragmentActivityw onPostExecute()później.

Problem polega na uzyskaniu prawidłowego odniesienia do nowego FragmentActivity. Nie ma na to metody ani getActivity()ani findById()czegoś podobnego. To forum jest pełne wątków na ten temat (np. Szukaj "Activity context in onPostExecute"). Niektóre z nich opisują obejścia (do tej pory nie znalazłem dobrego).

Może lepszym rozwiązaniem byłoby skorzystanie z Usługi do moich celów.

samo
źródło
2

Jest jedno alternatywne rozwiązanie (NIE najlepsze rozwiązanie) dla tego problemu, ale działa. Używając flagi możesz sobie z tym poradzić, jak poniżej

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

Możesz sprawdzić tę booleanwartość podczas wykonywania transakcji fragmentarycznej.

private void fragmentReplace(Fragment fragment, String fragmentTag){
    if (!isOnSaveInstanceStateCalled) {
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.layout_container, fragment, fragmentTag)
                .commit();
    }
}
Pankaj Kumar
źródło
1

Tyle ile jest warte; Wystąpił ten błąd w aplikacji, która uruchamiała usługi w tle. Na jednym z nich trzeba było wyświetlić użytkownikowi okno dialogowe przekroczenia limitu czasu. To okno dialogowe było przyczyną tego błędu, jeśli aplikacja nie działała już na pierwszym planie.

W naszym przypadku wyświetlenie okna dialogowego nie było przydatne, gdy aplikacja była w tle, więc po prostu śledziliśmy to (wartość logiczna oznaczona jako onPause i onResume), a następnie pokazujemy okno dialogowe tylko wtedy, gdy aplikacja jest rzeczywiście widoczna dla użytkownika.

hcpl
źródło
1

Rozwiązanie 1: Zastąp onSaveInstanceState()i usuń zawarte w nim super wywołanie.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Rozwiązanie 2: Zastąp onSaveInstanceState()i usuń swój fragment przed wywołaniem super

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

Ten problem występuje, gdy proces próbuje manipulować działaniem, które onStop()zostało wywołane. Niekoniecznie jest to powiązane z fragmentacją transakcji, ale także innymi metodami, takimi jak onBackPressed ().

Oprócz AsyncTask innym źródłem takiego problemu jest niewłaściwe umieszczenie subskrypcji wzorca magistrali. Zazwyczaj subskrypcja Event Bus lub RxBus jest rejestrowana podczas działania onCreate i wyrejestrowywana w onDestroy. Jeśli nowe działanie rozpocznie się i opublikuje zdarzenie przechwycone przez subskrybentów z poprzedniego działania, może spowodować ten błąd. Jeśli tak się stanie, jednym z rozwiązań jest przeniesienie rejestracji subskrypcji i wyrejestrowania do onStart()i onStop().

inmyth
źródło
1

To rozwiązało mój problem: Kod Kotlin:

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

Czym commitAllowingStateLoss()różni się od commit()?

Zgodnie z dokumentacją:

Podobnie, commit()ale pozwala na wykonanie zatwierdzenia po zapisaniu stanu działania. https://developer.android.com/reference/android/app/FragmentTransaction#commitAllowingStateLoss ()

PS: możesz wyświetlać okna dialogowe fragmentów lub ładować fragmenty tą metodą. Dotyczy obu.

Wajid Ali
źródło
0

Moja aplikacja ma fragment do załadowania w 3 sekundy, ale kiedy pierwszy ekran przygotowuje się do pokazania, wciskam przycisk home i wznawiam uruchomienie, pokazuje ten sam błąd, więc edytuje mój kod i działa bardzo płynnie:

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

UWAGA: dodaj commitAllowingStateLoss () zamiast commit ()

nobjta_9x_tq
źródło
0

Począwszy od wersji 24.0.0 biblioteki obsługi, możesz wywołać FragmentTransaction.commitNow()metodę, która zatwierdza tę transakcję synchronicznie zamiast wywoływania, commit()a następnieexecutePendingTransactions()

Volodymyr
źródło
0

IllegalStateException jest napotkany, jeśli zatwierdzasz transakcję fragmentową po utracie stanu przez działanie - działanie nie jest na pierwszym planie. Jest to często spotykane, gdy próbujesz zatwierdzić dowolny fragment w AsyncTask lub po żądaniu sieciowym.

Aby uniknąć tej awarii, wystarczy opóźnić transakcję fragmentaryczną, aż stan aktywności zostanie przywrócony. Oto jak to się robi

Zadeklaruj dwie prywatne zmienne boolowskie

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;

Teraz w onPostResume () i onPause ustawiamy i usuwamy ustawienie naszej zmiennej boolowskiej isTransactionSafe. Pomysł polega na oznaczeniu transakcji jako bezpiecznej tylko wtedy, gdy aktywność jest na pierwszym planie, więc nie ma szans na utratę statusu.

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

To, co zrobiliśmy do tej pory, uratuje przed IllegalStateException, ale nasze transakcje zostaną utracone, jeśli zostaną wykonane po przeniesieniu aktywności do tła, podobnie jak w przypadku commitAllowStateloss (). Aby pomóc w tym, mamy zmienną logiczną 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;
 }
}

W tym artykule szczegółowo wyjaśniono, dlaczego ten wyjątek został napotkany, i porównano różne metody jego rozwiązania. Wysoce rekomendowane

IrshadKumail
źródło
0

Miałem ten sam wyjątek i wypróbowałem wiele fragmentów, które znalazłem tutaj w tej dyskusji o przepływie stosu, ale żadne fragmenty nie działały dla mnie.

Ale udało mi się rozwiązać wszystkie problemy, podzielę się z Wami rozwiązaniami:

  • W pierwszej części: próbowałem pokazać DialogFragment na działaniu, ale z innej klasy java. Następnie po sprawdzeniu atrybutu tej instancji stwierdziłem, że była to stara instancja działania, a nie aktualnie uruchomione działanie. [Dokładniej, używałem socket.io i zapomniałem zrobić socket.off ("przykład", przykład) ... więc został dołączony do starej instancji działania. ]

  • W drugiej części: Próbowałem pokazać DialogFragment w działaniu, kiedy wróciłem do niego z zamiarem, ale kiedy sprawdziłem moje dzienniki, zobaczyłem, że kiedy próbowałem pokazać fragment, aktywność nadal nie była w metodzie onStart , więc spowodował awarię aplikacji, ponieważ nie znalazła klasy Activity, aby wyświetlić na niej fragment.

Kilka wskazówek: sprawdź niektóre atrybuty, jeśli nie używasz starej instancji swojej aktywności, z którą próbujesz pokazać swój fragment, lub sprawdź cykl życia swojej aktywności przed wyświetleniem fragmentu i upewnij się, że jesteś w onStart lub onResume przed pokazaniem go .

Mam nadzieję, że te wyjaśnienia ci pomogą.

Raj
źródło