web-dev-qa-db-ja.com

java.lang.IllegalStateException:onSaveInstanceStateの後にこのアクションを実行できません

アプリのサポートライブラリを使用しています。私のFragmentActivityでは、インターネットからデータをダウンロードするためにAsyncTaskを使用しています。 onPreExecute()メソッドでFragmentを追加し、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)

同様の問題に関する他のスレッドでは、onResume()メソッドが呼び出される前にonPostExecuteメソッドが呼び出されることが理由のようです。しかし、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)

次のようにAsynTaskを実装すると、IllegalStateExeptionが同じになります。これは、findFragmentById()メソッドが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();
    }

次のステップでは、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のid = 0x7f0a0002があります。ハンドラー内で、id = 0x7f0a0004のDummyFragmentが作成されます。 onPostExecute()では、両方のIDがnullです。 onPreExecute()では、MyFragmentActivityのアドレスは45e38358です。ただし、onPostExecute()ではnullです。ただし、どちらの方法でも、FragmentManagerアドレスは45e384a8です。 onPostExecuteは無効なFragmentManagerを使用していると思います。しかし、なぜ?

131
samo

次のように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();
            }
        });
}
95
Oleg Vaskevich

Oleg Vaskevichに感謝します。 WeakReferenceFragmentActivityを使用して問題を解決しました。私のコードは次のようになります。

public class MyFragmentActivity extends FragmentActivity implements OnFriendAddedListener {

    private static WeakReference<MyFragmentActivity> wrActivity = null;

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

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

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

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

この質問に対する正しい答えは次の方法だと思います。

public abstract int commitAllowingStateLoss ()

Commit()と似ていますが、アクティビティの状態が保存された後にコミットを実行できます。これは、アクティビティを後でその状態から復元する必要がある場合にコミットが失われる可能性があるため危険です。したがって、これはUIの状態がユーザーで予期せず変更しても問題ない場合にのみ使用してください。

上記の説明はこの方法に関するものです。

protected void onSaveInstanceState(Android.os.Bundle outState)

この問題は、デバイスがスリープ状態になったときに正確に発生します。

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

35
alex

短くて有効なソリューション:

簡単な手順に従ってください:

ステップ1:各フラグメントのonSaveInstanceState状態をオーバーライドします。そして、そこからスーパーメソッドを削除します。

@Override
public void onSaveInstanceState(Bundle outState) {
}

ステップ2:フラグメント操作中にCommitAllowingStateLoss();の代わりにcommit();を使用します。

fragmentTransaction.commitAllowingStateLoss();
24
Basbous

フラグメントを表示する前に、アクティビティisFinishing()を確認します。

例:

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

いくつかのフラグメントトランザクションコードをonResume()からonStart()に移動することで修正した同様の問題がありました。

より正確に言うと、私のアプリはランチャーです。 Androidホームボタンを押した後、ユーザーは自分の決定が記憶されるまでランチャーを選択できます。この時点で「戻る」と(たとえば、灰色がかった領域をタップして)、アプリがクラッシュしました。

たぶんこれは誰かを助けます。

5
Alex

この問題に対する代替ソリューションが1つあります(最良のソリューションではありません)が、機能します。フラグを使用すると、次のように処理できます

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

アクティビティをリークしているサブフラグメントからcommit()を呼び出していたので、それは私にとって起こりました。アクティビティをプロパティとして保持し、ローテーションアクティビティ変数はonAttach();によって更新されなかったため、保持された(setRetainInstance(true);)フラグメントによってゾンビアクティビティでトランザクションをコミットしようとしました。

2
Malachiasz

commitAllowingStateLoss()ではなくcommit()を使用します。

commit()を使用すると、状態が失われた場合に例外をスローできますが、commitAllowingStateLoss()は状態が失われずにトランザクションを保存するため、状態が失われた場合に例外をスローしません。

2
felhi

例外の理由は、FragmentActivityのランタイム中のAsyncTaskの再作成と、その後のonPostExecute()での破壊された前のFragmentActivityへのアクセスです。

問題は、新しいFragmentActivityへの有効な参照を取得することです。 getActivity()でもfindById()でも、これに類するものでもありません。このフォーラムには、この問題に応じたスレッドがいっぱいです(例:"Activity context in onPostExecute"の検索)。それらのいくつかは回避策を説明しています(今までは良いものを見つけられませんでした)。

たぶん、私の目的のためにサービスを使用する方が良い解決策でしょう。

2
samo

解決策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
Lingkun Kong

それが価値があるもののために。バックグラウンドでサービスを実行しているアプリでこのエラーが発生しました。それらの1つでは、タイムアウトダイアログをユーザーに表示する必要がありました。このダイアログは、アプリがフォアグラウンドで実行されなくなった場合にこのエラーを引き起こす問題でした。

このケースでは、アプリがバックグラウンドにあるときにダイアログを表示することは役に立たなかったため、それを追跡し(boolean ononuse on onResume)、アプリが実際にユーザーに表示されているときにのみダイアログを表示します。

1
hcpl

この問題は、プロセスがonStop()が呼び出されたアクティビティを操作しようとしたときに発生します。これは必ずしもフラグメントトランザクションに関連付けられているわけではなく、onBackPressed()などの他のメソッドにも関連付けられています。

AsyncTaskに加えて、このような問題の別の原因は、バスパターンのサブスクリプションの配置ミスです。通常、イベントバスまたはRxBusのサブスクリプションは、アクティビティのonCreate中に登録され、onDestroyで登録解除されます。新しいアクティビティが開始され、前のアクティビティからサブスクライバーによってインターセプトされたイベントを発行すると、このエラーが発生する場合があります。これが発生した場合、1つの解決策は、サブスクリプションの登録と登録解除をonStart()およびonStop()に移動することです。

1
inmyth

サポートライブラリバージョン24.0.0以降では、FragmentTransaction.commitNow()に続いてcommit()を呼び出す代わりに、このトランザクションを同期的にコミットするexecutePendingTransactions()メソッドを呼び出すことができます。

アクティビティが状態を失った後にフラグメントトランザクションをコミットすると、IllegalStateExceptionが発生します。アクティビティはフォアグラウンドにありません。これは、AsyncTaskでフラグメントをコミットしようとしたとき、またはネットワーク要求の後によく発生します。

このクラッシュを回避するには、アクティビティの状態が復元されるまでフラグメントトランザクションを遅らせるだけです。以下はその方法です

2つのプライベートブール変数を宣言する

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
IrshadKumail

私のアプリには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();
        }
    });

注: commit()の代わりにcommitAllowingStateLoss()を追加

0
nobjta_9x_tq

私は同じ例外を持っていて、このstackoverflowの議論でここで見つけたスニペットをたくさん試しましたが、スニペットはうまくいきませんでした。

しかし、私はすべての問題を解決することができました、私はあなたと解決策を共有します:

  • 最初の部分では、別のJavaクラスからのActivityでDialogFragmentを表示しようとしました。次に、そのインスタンスの属性を確認すると、それがアクティビティの古いインスタンスであり、現在実行中のアクティビティではないことがわかりました。 [もっと正確に、私はsocket.ioを使用していたので、socket.off( "example"、example)を実行するのを忘れていたので、アクティビティの古いインスタンスにアタッチしました。 ]

  • 第二部:意図で戻ったときにアクティビティにDialogFragmentを表示しようとしていましたが、ログを確認すると、フラグメントを表示しようとしたときにアクティビティがまだonStartメソッドにないことがわかりました、そのため、フラグメントを表示するActivityクラスが見つからなかったため、アプリがクラッシュしました。

いくつかのヒント:フラグメントを表示しようとしているアクティビティの古いインスタンスを使用していない場合は、いくつかの属性を確認するか、フラグメントを表示する前にアクティビティのライフサイクルを確認し、表示する前にonStartまたはonResumeにいることを確認してください。

これらの説明がお役に立てば幸いです。

0
Raj