java.lang.IllegalStateException: Tidak dapat melakukan tindakan ini setelah onSaveInstanceState

136

Saya menggunakan pustaka dukungan untuk aplikasi saya. Dalam FragmentActivity saya, saya menggunakan AsyncTask untuk mengunduh data dari internet. Dalam metode onPreExecute () saya menambahkan Fragment dan dalam metode onPostExecute () saya menghapusnya lagi. Ketika orientasi diubah di antara keduanya, saya mendapatkan pengecualian yang disebutkan di atas. Silakan lihat detailnya:

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

Saya mendapatkan LogCut berikut:

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)

Di utas lain tentang masalah serupa, alasannya tampaknya karena metode onPostExecute dipanggil sebelum metode onResume () dipanggil. Tapi saya mendapatkan pengecualian meskipun onResume () dipanggil sebelumnya.

Apakah ada yang tahu apa yang salah?

Aktivitasnya terlihat seperti ini:

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

Saat menggunakan commitAllowingStateLoss () saya mendapatkan pengecualian berikut:

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)

Saya mendapatkan IllegalStateExeption yang sama ketika saya menerapkan AsynTask sebagai berikut, karena metode findFragmentById () mengembalikan pointer nol.

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

Pada langkah selanjutnya saya menggunakan handler untuk menambah dan menghapus DummyFragment. Selain itu saya telah menambahkan beberapa keluaran debug.

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

Saya mendapatkan LogCut berikut:

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)

Di onPreExecute () FriendListFragment memiliki id = 0x7f0a0002. Di dalam handler, DummyFragment dibuat dengan id = 0x7f0a0004. Dalam onPostExecute () kedua ID tersebut adalah null. Di onPreExecute (), alamat MyFragmentActivity adalah 45e38358. tetapi di onPostExecute () nilainya null. Namun di kedua metode, alamat FragmentManager adalah 45e384a8. Saya kira onPostExecute menggunakan FragmentManager yang tidak valid. Tapi kenapa?

samo
sumber
1
Saya mengalami masalah ini sekali dan memperbaikinya dengan mengganti komit dengan ini: commitAllowingStateLoss (), dapatkah Anda mencoba ini?
Cata
Saya sudah mencoba ini, tetapi tidak berhasil. Menurut LogCat, Fragmen harus dalam keadaan yang benar.
samo
Bisakah Anda memposting kode Aktivitas Anda?
Robert Estivill
Ketika saya menggunakan commitAllowingStateLoss () saya mendapatkan pengecualian yang berbeda (lihat di atas).
samo
6
Bagi Anda yang masih mencari solusi ... lihat posting blog tentang topik ini untuk informasi lebih lanjut.
Alex Lockwood

Jawaban:

97

Anda harus melakukan transaksi Handlersebagai berikut:

@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
sumber
12
Itu tidak membantu. Perilakunya sama seperti sebelumnya.
samo
@samo tolong, apakah Anda dapat menyelesaikan masalah ini? Saya memiliki tautan
Lisa Anne
3
Pertimbangkan kode ini:private static WeakReference<FragmentActivity> mActivity = null;
Oleg Vaskevich
2
Singkatnya, WeakReferencemencegah Anda membocorkan aktivitas ... Anda perlu memanggil mActivity.get()untuk benar-benar mendapatkan instance, dan akan bernilai null jika aktivitas dimusnahkan. Untuk memperbaruinya, Anda perlu menulis mActivity = new WeakReference<FragmentActivity>(this);- tempat yang bagus onCreate()- yang akan memperbarui referensi.
Oleg Vaskevich
107
Bagi Anda yang masih mencari solusi ... lihat posting blog tentang topik ini untuk informasi lebih lanjut.
Alex Lockwood
55

Terima kasih Oleg Vaskevich. Menggunakan salah satu WeakReferencedari masalah yang FragmentActivitydipecahkan. Kode saya terlihat sebagai berikut sekarang:

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
sumber
Ide referensi yang lemah memang ide yang sangat cerdas, ini akan memungkinkan objek dengan mudah dikumpulkan dari sampah bila diperlukan. jempol samo!
Jimmy Ilenloa
Mengapa statis digunakan di sini? Bagaimana jika saya menggunakan MyFragmentActivity mActivity = this ?With out static & WeakReference
Bharath
Referensi statis adalah teknik yang sangat buruk, Anda sebaiknya mengikat asynchtask Anda ke siklus proses dan membatalkannya jika diperlukan
breakline
38

Saya yakin jawaban yang benar untuk pertanyaan ini adalah metode berikut.

public abstract int commitAllowingStateLoss ()

Seperti commit () tetapi mengizinkan komit untuk dieksekusi setelah status aktivitas disimpan. Ini berbahaya karena komit bisa hilang jika aktivitas nanti perlu dipulihkan dari statusnya, jadi ini hanya boleh digunakan untuk kasus saat status UI berubah secara tidak terduga pada pengguna tidak masalah.

Uraian di atas berkaitan dengan metode ini.

protected void onSaveInstanceState(android.os.Bundle outState)

Masalah ini terjadi justru saat perangkat tidur.

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

alex
sumber
25

Solusi Singkat Dan Bekerja:

Ikuti Langkah Sederhana:

Langkah 1 : Ganti onSaveInstanceStatestatus di masing-masing fragmen. Dan hapus metode super darinya.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Langkah 2 : Gunakan CommitAllowingStateLoss();sebagai ganti commit();while operasi fragmen.

fragmentTransaction.commitAllowingStateLoss();
Basbous
sumber
2
Terima kasih. Ini berhasil untuk saya, tetapi saya tahu itu bukan solusi terbaik.
wendigo
2
menghapus metode super, juga menonaktifkan penyimpanan status fragmen Anda.
Juan Mendez
1
Terima kasih banyak. Ini menghasilkan pengecualian, solusi ini bekerja dengan baik ..
Deepak Ganachari
11

Periksa apakah aktivitas tersebut isFinishing()sebelum menampilkan fragmen.

Contoh:

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

Saya memiliki masalah serupa yang saya perbaiki dengan memindahkan beberapa kode transaksi fragmen dari onResume()ke dalam onStart().

Lebih tepatnya: Aplikasi saya adalah peluncur. Setelah menekan tombol Beranda Android, pengguna dapat memilih peluncur sampai keputusannya diingat. Saat "kembali" pada titik ini (misalnya dengan mengetuk di area abu-abu) aplikasi macet.

Mungkin ini membantu seseorang.

Alex
sumber
4

Gunakan commitAllowingStateLoss()sebagai ganti commit() .

Saat digunakan commit()akan memunculkan eksepsi jika terjadi kerugian negara tetapi commitAllowingStateLoss()menyimpan transaksi tanpa kerugian negara sehingga tidak memunculkan eksepsi jika terjadi kerugian negara.

felhi
sumber
2

Itu terjadi pada saya, karena saya memanggil commit()dari subfragmen yang membocorkan aktivitas. Itu menyimpan aktivitas sebagai properti dan pada variabel aktivitas rotasi tidak diperbarui oleh onAttach();Jadi saya mencoba melakukan transaksi pada Aktivitas zombie dengan (setRetainInstance(true);)fragmen yang dipertahankan .

Malachiasz
sumber
2

Alasan pengecualian adalah pembuatan ulang FragmentActivityselama runtime AsyncTaskdan akses ke yang sebelumnya, dimusnahkan FragmentActivitydalamonPostExecute() sesudahnya.

Masalahnya adalah mendapatkan referensi yang valid ke yang baru FragmentActivity. Tidak ada metode untuk ini, getActivity()atau findById()atau yang serupa. Forum ini penuh dengan utas tentang masalah ini (mis. Cari"Activity context in onPostExecute" ). Beberapa dari mereka menjelaskan solusi (sampai sekarang saya tidak menemukan solusi yang bagus).

Mungkin ini akan menjadi solusi yang lebih baik untuk menggunakan Layanan untuk tujuan saya.

samo
sumber
2

Ada satu solusi alternatif (BUKAN solusi terbaik) untuk masalah ini, tetapi berhasil. Menggunakan flag Anda bisa mengatasinya, seperti di bawah ini

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

Dan Anda dapat memeriksa booleannilai ini saat melakukan transaksi fragmen.

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

Untuk apa nilainya; Saya mengalami kesalahan ini pada aplikasi yang menjalankan layanan di latar belakang. Di salah satunya, dialog batas waktu harus ditampilkan kepada pengguna. Dialog itu adalah masalah yang menyebabkan kesalahan ini jika aplikasi tidak lagi berjalan di latar depan.

Dalam kasus kami, menampilkan dialog tidak berguna saat aplikasi berada di latar belakang jadi kami terus melacaknya (boolean ditandai onPause en onResume) dan kemudian hanya menampilkan dialog saat aplikasi benar-benar terlihat oleh pengguna.

hcpl
sumber
1

Solusi 1: TimpaonSaveInstanceState() dan hapus panggilan super di dalamnya.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Solusi 2: Timpa onSaveInstanceState()dan hapus fragmen Anda sebelum panggilan super

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

Masalah ini terjadi ketika suatu proses mencoba memanipulasi Aktivitas yang onStop() telah dipanggil. Ini tidak selalu terkait dengan transaksi fragmen tetapi juga metode lain seperti onBackPressed ().

Selain AsyncTask, sumber masalah lainnya adalah kesalahan penempatan langganan pola bus. Biasanya langganan Event Bus atau RxBus terdaftar selama onCreate Aktivitas dan didaftarkan di onDestroy. Jika Aktivitas baru dimulai dan menerbitkan acara yang dicegat oleh pelanggan dari Aktivitas sebelumnya, maka hal itu mungkin menghasilkan kesalahan ini. Jika ini terjadi, salah satu solusinya adalah dengan memindahkan pendaftaran langganan dan pembatalan pendaftaran ke onStart()dan onStop().

dalam mitos
sumber
1

Ini memecahkan masalah saya: Kode Kotlin:

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

Apa commitAllowingStateLoss()bedanya dengan commit()?

Sesuai dokumentasi:

Suka commit()tetapi mengizinkan komit untuk dieksekusi setelah status aktivitas disimpan. https://developer.android.com/reference/android/app/FragmentTransaction#commitAllowingStateLoss ()

PS: Anda dapat menampilkan Dialog Fragmen atau dapat memuat fragmen dengan metode ini. Berlaku untuk keduanya.

Wajid Ali
sumber
0

Aplikasi saya memiliki fragmen untuk dimuat dalam 3 detik, tetapi ketika layar pertama bersiap untuk ditampilkan, saya menekan tombol beranda dan melanjutkan menjalankannya, itu menunjukkan kesalahan yang sama, jadi Ini mengedit kode saya dan itu berjalan sangat lancar:

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

CATATAN: tambahkan commitAllowingStateLoss () daripada commit ()

nobjta_9x_tq
sumber
0

Mulai dari pustaka dukungan versi 24.0.0, Anda dapat memanggil FragmentTransaction.commitNow()metode yang melakukan transaksi ini secara sinkron alih-alih memanggil commit()diikuti olehexecutePendingTransactions()

Volodymyr
sumber
0

IllegalStateException ditemui jika Anda melakukan transaksi fragmen apa pun setelah aktivitas kehilangan statusnya- Aktivitas tidak berada di latar depan. Ini biasanya ditemui saat Anda mencoba memasukkan fragmen apa pun di AsyncTask atau setelah permintaan jaringan.

Untuk menghindari crash ini, Anda hanya perlu menunda transaksi fragmen apa pun hingga status aktivitas dipulihkan. Berikut ini adalah cara melakukannya

Deklarasikan dua variabel boolean privat

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;

Sekarang di onPostResume () dan onPause kita menyetel dan menghapus variabel boolean isTransactionSafe. Idealnya adalah menandai transaksi aman hanya jika aktivitas berada di latar depan sehingga tidak ada peluang stateloss.

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

Apa yang telah kita lakukan sejauh ini akan menyelamatkan dari IllegalStateException tetapi transaksi kita akan hilang jika dilakukan setelah aktivitas berpindah ke latar belakang, seperti commitAllowStateloss (). Untuk membantu itu kami memiliki variabel boolean 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;
 }
}

Artikel ini menjelaskan secara cukup rinci mengapa pengecualian ini ditemui dan membandingkan berbagai metode untuk mengatasinya. Sangat dianjurkan

IrshadKumail
sumber
0

Saya memiliki pengecualian yang sama dan saya mencoba banyak cuplikan yang saya temukan di sini pada diskusi stackoverflow ini, tetapi tidak ada cuplikan yang berhasil untuk saya.

Tetapi saya dapat menyelesaikan semua masalah, saya akan berbagi dengan Anda solusinya:

  • Di bagian Pertama: Saya mencoba menampilkan DialogFragment pada Aktivitas tetapi dari kelas java lain. Kemudian dengan memeriksa atribut dari instance itu, saya menemukan bahwa itu adalah instance lama dari Activity, itu bukan Activity yang sedang berjalan. [Lebih tepatnya saya menggunakan socket.io, dan saya lupa melakukan socket.off ("contoh", contoh) ... jadi itu dilampirkan ke instance lama dari aktivitas. ]

  • Di bagian Kedua: Saya mencoba menampilkan DialogFragment dalam Aktivitas ketika saya kembali ke sana dengan maksud, tetapi ketika saya memeriksa log saya, saya melihat bahwa ketika mencoba menampilkan fragmen, aktivitas masih belum dalam metode onStart , sehingga membuat aplikasi crash karena tidak menemukan kelas Activity untuk menampilkan fragmen di atasnya.

Beberapa tip: periksa dengan beberapa atribut jika Anda tidak menggunakan instance lama dari aktivitas Anda yang ingin Anda tampilkan fragmennya, atau periksa daur hidup aktivitas Anda sebelum menampilkan fragmen dan pastikan Anda berada di onStart atau onResume sebelum menampilkannya .

Saya harap penjelasan itu akan membantu Anda.

Raj
sumber