java.lang.IllegalStateException: не может выполнить это действие после onSaveInstanceState


135

Я использую библиотеку поддержки для моего приложения. В своей FragmentActivity я использую AsyncTask для загрузки данных из Интернета. В методе onPreExecute () я добавляю фрагмент, а в методе onPostExecute () я снова его удаляю. Когда ориентация меняется между ними, я получаю вышеупомянутое исключение. Пожалуйста, посмотрите на детали:

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

Я получаю следующий 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)

В других потоках о подобных проблемах причина, по-видимому, заключается в том, что метод onPostExecute вызывается до вызова метода onResume (). Но я получаю исключение, хотя onResume () вызывается раньше.

Кто-нибудь знает в чем дело?

Активность выглядит так:

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

При использовании commitAllowingStateLoss () я получаю следующее исключение:

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)

Я получаю то же IllegalStateExeption при реализации AsynTask следующим образом, потому что метод findFragmentById () возвращает нулевой указатель.

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

На следующем шаге я использую обработчик для добавления и удаления DummyFragment. Кроме того, я добавил еще несколько отладочных сообщений.

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

Я получаю следующий 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)

В onPreExecute () FriendListFragment имеет идентификатор = 0x7f0a0002. Внутри обработчика DummyFragment создается с id = 0x7f0a0004. В onPostExecute () оба идентификатора равны нулю. В onPreExecute () адрес MyFragmentActivity - 45e38358. но в onPostExecute () он является нулевым. Но в обоих методах адрес FragmentManager - 45e384a8. Я предполагаю, что onPostExecute использует недопустимый FragmentManager. Но почему?


1
У меня была однажды эта проблема, и я исправил ее, заменив коммит следующим: commitAllowingStateLoss (), вы можете попробовать это?
Cata

Я уже пробовал это, но безуспешно. Согласно LogCat Фрагмент должен быть в правильном состоянии.
Само

Можете ли вы опубликовать свой код активности?
Роберт Эстивилл

Когда я использую commitAllowingStateLoss (), я получаю другое исключение (см. Выше).
Само

6
Для тех из вас, кто все еще ищет решение ... см. Этот пост в блоге на эту тему для получения дополнительной информации.
Алекс Локвуд

Ответы:


97

Вы должны сделать транзакцию Handlerследующим образом:

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

12
Это не помогает Поведение такое же, как и раньше.
Само

@ Само, пожалуйста, вы смогли решить проблему? У меня очень похожая ситуация ссылку
Лиза Энн

3
Рассмотрим этот код: private static WeakReference<FragmentActivity> mActivity = null;
Олег Васкевич

2
В двух словах, WeakReferenceпредотвращает утечку действия ... вам нужно позвонить, mActivity.get()чтобы получить экземпляр, и оно будет нулевым, если действие было уничтожено. Чтобы обновить его, вам нужно написать mActivity = new WeakReference<FragmentActivity>(this);- в хорошем месте onCreate()- что обновит ссылку.
Олег Васкевич

107
Для тех из вас, кто все еще ищет решение ... см. Этот пост в блоге на эту тему для получения дополнительной информации.
Алекс Локвуд

55

Спасибо Олегу Васкевичу. Используя WeakReferenceиз FragmentActivityрешить эту проблему. Мой код выглядит следующим образом:

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

идея со слабыми ссылками действительно очень умная, она позволяет легко собирать мусор при необходимости. недурно само!
Джимми Иленлоа

Почему здесь используется статика? Что делать, если я использую MyFragmentActivity mActivity = this ?Без статических и слабых ссылок
Бхарат

Статическая ссылка довольно плохая инженерия, вам лучше привязать свою асинхронную задачу к жизненному циклу и отменить, когда это необходимо
перерыв

38

Я считаю, что правильный ответ на этот вопрос заключается в следующем методе.

public abstract int commitAllowingStateLoss ()

Как и commit (), но позволяет выполнять коммит после сохранения состояния действия. Это опасно, потому что фиксация может быть потеряна, если впоследствии необходимо восстановить активность из ее состояния, поэтому ее следует использовать только в тех случаях, когда вполне допустимо непредвиденное изменение состояния пользовательского интерфейса для пользователя.

Приведенное выше описание относится к этому способу.

protected void onSaveInstanceState(android.os.Bundle outState)

Эта проблема возникает именно тогда, когда устройство переходит в режим сна.

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


25

Краткое и рабочее решение:

Следуйте простым шагам:

Шаг 1 : Переопределить onSaveInstanceStateсостояние в соответствующем фрагменте. И удалите супер метод из него.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Шаг 2 : Используйте CommitAllowingStateLoss();вместо операций commit();while фрагмент.

fragmentTransaction.commitAllowingStateLoss();

2
Спасибо. Это работает для меня, но я знаю, что это не лучшее решение.
Вендиго

2
удаление супер-метода, также отключает сохранение ваших состояний фрагмента.
Хуан Мендес

1
Спасибо большое. Это генерировало исключение, это решение работало хорошо ..
Дипак

11

Проверьте, если активность, isFinishing()прежде чем показывать фрагмент.

Пример:

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

5

У меня была похожая проблема, которую я исправил, переместив фрагмент кода транзакции из onResume()в onStart().

Чтобы быть более точным: мое приложение запуска. После нажатия кнопки «Домой» на Android пользователь может выбрать средство запуска, пока его / ее решение не запомнится. При переходе «назад» в этот момент (например, нажав в сероватой области) приложение зависло.

Может быть, это кому-нибудь поможет.


4

Используйте commitAllowingStateLoss()вместо commit() .

при использовании commit()он может выдать исключение, если происходит потеря состояния, но commitAllowingStateLoss()сохраняет транзакцию без потери состояния, чтобы не вызывать исключение в случае потери состояния.


2

Это произошло для меня, потому что я вызывал commit()субфрагмент, который пропускал активность. Он сохранил активность как свойство, а переменная активности ротации не была обновлена, onAttach();поэтому я пытался зафиксировать транзакцию в активности зомби по сохраненному (setRetainInstance(true);)фрагменту.


2

Причина исключения является повторным созданием FragmentActivityво время выполнения из AsyncTaskи доступа к предыдущему, разрушенному FragmentActivityв onPostExecute()потом.

Проблема в том, чтобы получить действительную ссылку на новое FragmentActivity. Там нет способа для этого ни getActivity()ни findById()или что - то подобное. Этот форум полон тем по этой проблеме (например, поиск по"Activity context in onPostExecute" ). Некоторые из них описывают обходные пути (до сих пор я не нашел хорошего).

Возможно, было бы лучшим решением использовать Сервис для моих целей.


2

Существует одно альтернативное решение (НЕ лучшее решение) для этой проблемы, но оно работает. С помощью флага вы можете справиться с этим, как показано ниже

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

И вы можете проверить это booleanзначение при выполнении фрагмента транзакции.

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

1

Для чего это стоит; У меня была эта ошибка в приложении, которое запускало службы в фоновом режиме. На одном из них диалоговое окно тайм-аута должно было быть показано пользователю. Этот диалог был причиной возникновения этой ошибки, если приложение больше не работало на переднем плане.

В нашем случае показ диалога был бесполезен, когда приложение находилось в фоновом режиме, поэтому мы просто отслеживали его (логическое значение onPause en onResume), а затем отображали диалоговое окно только тогда, когда приложение действительно видимо для пользователя.


1

Решение 1: переопределить onSaveInstanceState()и удалить в нем супер-вызов.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Решение 2: переопределить onSaveInstanceState()и удалить свой фрагмент перед супер вызовом

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

1

Эта проблема возникает, когда процесс пытается манипулировать действием, onStop()которое было вызвано. Он не обязательно привязан к фрагментной транзакции, но также и к другим методам, таким как onBackPressed ().

В дополнение к AsyncTask, другим источником такой проблемы является неправильное размещение подписки шаблона шины. Обычно подписка на Event Bus или RxBus регистрируется во время действия onCreate и отменяется в onDestroy. Если новое действие начинается и публикует событие, перехваченное подписчиками из предыдущего действия, то это может привести к этой ошибке. Если это произойдет, то одним из решений будет перемещение регистрации и отмены регистрации подписки в onStart()и onStop().


1

Это решило мою проблему: Кодлин Kotlin:

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

Чем это commitAllowingStateLoss()отличается от commit()?

Согласно документации:

Нравится, commit()но позволяет выполнить коммит после сохранения состояния действия. https://developer.android.com/reference/android/app/FragmentTransaction#commitAllowingStateLoss ()

PS: вы можете показать Fragment Dialogs или можете загружать фрагменты этим методом. Применимо для обоих.


0

У моего приложения есть фрагмент для загрузки в течение 3 секунд, но когда первый экран готовится к показу, я нажимаю кнопку «Домой» и возобновляю его запуск, он показывает ту же ошибку, поэтому он редактирует мой код и работает очень гладко:

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

ПРИМЕЧАНИЕ: добавьте commitAllowingStateLoss () вместо commit ()


0

Начиная с версии 24.0.0 библиотеки поддержки, вы можете вызвать FragmentTransaction.commitNow()метод, который синхронно фиксирует эту транзакцию, вместо вызова с commit()последующимexecutePendingTransactions()


0

IllegalStateException встречается, если вы фиксируете какую-либо фрагментную транзакцию после того, как активность потеряла свое состояние. Активность не находится на переднем плане. Это часто встречается при попытке зафиксировать любой фрагмент в AsyncTask или после сетевого запроса.

Чтобы избежать этого сбоя, вам просто нужно отложить любую транзакцию фрагмента, пока состояние активности не будет восстановлено. Вот как это делается

Объявите две частные логические переменные

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;

Теперь в onPostResume () и onPause мы устанавливаем и удаляем нашу логическую переменную isTransactionSafe. Идея состоит в том, чтобы помечать транзакции как безопасные только тогда, когда активность находится на переднем плане, поэтому нет шансов потерять состояние.

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

То, что мы сделали до сих пор, спасет от IllegalStateException, но наши транзакции будут потеряны, если они будут выполнены после того, как действие переместится в фоновый режим, что-то вроде commitAllowStateloss (). Чтобы помочь с этим, у нас есть логическая переменная 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;
 }
}

В этой статье довольно подробно объясняется, почему встречается это исключение, и сравниваются различные методы для его устранения. Настоятельно рекомендуется


0

У меня было то же исключение, и я попробовал много фрагментов, которые я нашел здесь в этом обсуждении потока стека, но никакие фрагменты не работали для меня.

Но мне удалось решить все вопросы, я поделюсь с вами решениями:

  • В первой части: я пытался показать DialogFragment в Activity, но из другого Java-класса. Затем, проверив атрибут этого экземпляра, я обнаружил, что это был старый экземпляр Activity, а не текущий запущенный Activity. [Более точно, я использовал socket.io, и я забыл сделать socket.off («пример», пример) ... так, чтобы он был привязан к старому экземпляру действия. ]

  • Во второй части: я пытался показать DialogFragment в Activity, когда возвращаюсь к нему с намерением, но когда я проверял свои журналы, я видел, что когда он пытался показать фрагмент, действие все еще не было в методе onStart , так что это привело к сбою приложения, потому что он не нашел класс Activity, чтобы показать фрагмент на нем.

Несколько советов: проверьте с некоторыми атрибутами, если вы не используете старый экземпляр своей активности, с которым вы пытаетесь показать свой фрагмент, или проверьте жизненный цикл своей активности, прежде чем показывать свой фрагмент, и убедитесь, что вы находитесь в onStart или onResume, прежде чем показывать его. ,

Я надеюсь, что эти объяснения помогут вам.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.