java.lang.IllegalStateException: ไม่สามารถดำเนินการนี้หลังจาก onSaveInstanceState


136

ฉันใช้ไลบรารีการสนับสนุนสำหรับแอปของฉัน ใน 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)

ในเธรดอื่น ๆ เกี่ยวกับปัญหาที่คล้ายกันสาเหตุดูเหมือนว่าเมธอด 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);
    }
}

เมื่อใช้ commitsAllowingStateLoss () ฉันได้รับข้อยกเว้นต่อไปนี้:

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 มี id = 0x7f0a0002 ภายในตัวจัดการ DummyFragment ถูกสร้างขึ้นด้วย id = 0x7f0a0004 ใน onPostExecute () ID ทั้งสองเป็นโมฆะ ใน onPreExecute () ที่อยู่ของ MyFragmentActivity คือ 45e38358 แต่ใน onPostExecute () มันเป็นโมฆะ แต่ในทั้งสองวิธีที่อยู่ FragmentManager คือ 45e384a8 ฉันเดาว่า onPostExecute ใช้ FragmentManager ที่ไม่ถูกต้อง แต่ทำไม?


1
ฉันมีปัญหานี้หนึ่งครั้งและได้รับการแก้ไขโดยการแทนที่การกระทำด้วยสิ่งนี้: commitsAllowingStateLoss () ลองทำดูได้ไหม
Cata

ฉันได้ลองแล้ว แต่ไม่ประสบความสำเร็จ ตาม LogCat Fragment ควรอยู่ในสถานะที่ถูกต้อง
samo

กรุณาโพสต์รหัสกิจกรรมของคุณได้ไหม
Robert Estivill

เมื่อฉันใช้ CommitAllowingStateLoss () ฉันได้รับข้อยกเว้นที่แตกต่างออกไป (ดูด้านบน)
samo

6
สำหรับผู้ที่ยังคงค้นหาวิธีแก้ปัญหา ... ดูบทความในบล็อกเกี่ยวกับหัวข้อนี้สำหรับข้อมูลเพิ่มเติม
Alex Lockwood

คำตอบ:


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
มันไม่ช่วยอะไร พฤติกรรมก็เหมือนเดิม
samo

@samo คุณช่วยแก้ปัญหาได้ไหม ฉันมีลิงค์
Lisa Anne

3
พิจารณารหัสนี้:private static WeakReference<FragmentActivity> mActivity = null;
Oleg Vaskevich

2
โดยสรุปWeakReferenceจะป้องกันไม่ให้คุณรั่วไหลของกิจกรรม ... คุณต้องโทรmActivity.get()เพื่อรับอินสแตนซ์จริงและจะเป็นโมฆะหากกิจกรรมถูกทำลาย ในการอัปเดตคุณจะต้องเขียนmActivity = new WeakReference<FragmentActivity>(this);- สถานที่ที่ดีอยู่ในonCreate()- ซึ่งจะอัปเดตข้อมูลอ้างอิง
Oleg Vaskevich

107
สำหรับผู้ที่ยังคงค้นหาวิธีแก้ปัญหา ... ดูบทความในบล็อกเกี่ยวกับหัวข้อนี้สำหรับข้อมูลเพิ่มเติม
Alex Lockwood

55

ขอบคุณ Oleg Vaskevich ใช้ a 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();
            }
        }

แนวคิดอ้างอิงที่อ่อนแอนั้นเป็นแนวคิดที่ชาญฉลาดมากซึ่งจะช่วยให้สามารถเก็บขยะได้ง่ายเมื่อจำเป็น ยกนิ้วให้ samo!
Jimmy Ilenloa

เหตุใดจึงใช้แบบคงที่ที่นี่ จะเกิดอะไรขึ้นถ้าฉันใช้ MyFragmentActivity mActivity = this ?With out static & WeakReference
Bharath

อ้างอิงแบบคงที่เป็นวิศวกรรมที่ไม่ดีงามคุณค่อนข้างจะผูก asynchtask ของคุณเพื่อวงจรและยกเลิกเมื่อมันจำเป็น
breakline

38

ฉันเชื่อว่าคำตอบที่ถูกต้องสำหรับคำถามนี้คือวิธีการต่อไปนี้

public abstract int commitAllowingStateLoss ()

เช่นเดียวกับการกระทำ () แต่อนุญาตให้ดำเนินการคอมมิตได้หลังจากบันทึกสถานะของกิจกรรมแล้ว สิ่งนี้เป็นอันตรายเนื่องจากการคอมมิตอาจสูญหายได้หากกิจกรรมจำเป็นต้องได้รับการกู้คืนจากสถานะในภายหลังดังนั้นควรใช้เฉพาะในกรณีที่สถานะ UI สามารถเปลี่ยนแปลงได้โดยไม่คาดคิดกับผู้ใช้

คำอธิบายข้างต้นเกี่ยวข้องกับวิธีนี้

protected void onSaveInstanceState(android.os.Bundle outState)

ปัญหานี้เกิดขึ้นอย่างแม่นยำเมื่ออุปกรณ์เข้าสู่โหมดสลีป

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


25

โซลูชันระยะสั้นและใช้งานได้:

ทำตามขั้นตอนง่ายๆ:

ขั้นตอนที่ 1 : แทนที่onSaveInstanceStateสถานะในส่วนที่เกี่ยวข้อง และลบ super method ออกไป

@Override
public void onSaveInstanceState(Bundle outState) {
}

ขั้นตอนที่ 2 : ใช้CommitAllowingStateLoss();แทนcommit();การดำเนินการ while Fragment

fragmentTransaction.commitAllowingStateLoss();

2
ขอบคุณ. วิธีนี้ใช้ได้ผลสำหรับฉัน แต่ฉันรู้ว่านั่นไม่ใช่ทางออกที่ดีที่สุด
wendigo

2
การลบ super method ปิดใช้งานการบันทึกสถานะแฟรกเมนต์ของคุณ
Juan Mendez

1
ขอบคุณมากมันสร้างข้อยกเว้นโซลูชันนี้ใช้ได้ดี ..
Deepak Ganachari

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

เพื่อสิ่งที่คุ้มค่า ฉันพบข้อผิดพลาดนี้ในแอปที่กำลังเรียกใช้บริการอยู่เบื้องหลัง ในหนึ่งในนั้นจะต้องแสดงกล่องโต้ตอบการหมดเวลาให้กับผู้ใช้ กล่องโต้ตอบนั้นเป็นปัญหาที่ทำให้เกิดข้อผิดพลาดนี้หากแอปไม่ทำงานในเบื้องหน้าอีกต่อไป

ในกรณีของเราการแสดงกล่องโต้ตอบไม่มีประโยชน์เมื่อแอปอยู่ในพื้นหลังดังนั้นเราจึงติดตามสิ่งนั้น (ตั้งค่าสถานะบูลีนเมื่อหยุดชั่วคราว 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 หากกิจกรรมใหม่เริ่มต้นและเผยแพร่เหตุการณ์ที่ถูกขัดขวางโดยสมาชิกจากกิจกรรมก่อนหน้านั้นอาจทำให้เกิดข้อผิดพลาดนี้ หากเกิดเหตุการณ์นี้แล้วหนึ่งวิธีการแก้ปัญหาคือการย้ายการลงทะเบียนสมัครสมาชิกและ de-ลงทะเบียนและ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 () แทนการกระทำ ()


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 แนวคิดคือการทำเครื่องหมายว่า trasnsaction ปลอดภัยก็ต่อเมื่อกิจกรรมนั้นอยู่เบื้องหน้าดังนั้นจึงไม่มีโอกาสเกิด 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();
    }
}

สิ่งที่เราทำจนถึงตอนนี้จะช่วยให้รอดพ้นจาก 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

ฉันมีข้อยกเว้นเหมือนกันและฉันลองใช้ตัวอย่างข้อมูลมากมายที่ฉันพบที่นี่ในการสนทนา stackoverflow นี้ แต่ไม่มีตัวอย่างใดที่เหมาะกับฉัน

แต่ฉันสามารถแก้ไขปัญหาทั้งหมดได้ฉันจะแบ่งปันวิธีแก้ปัญหากับคุณ:

  • ในส่วนแรก: ฉันพยายามแสดง DialogFragment ในกิจกรรม แต่มาจากคลาส java อื่น จากนั้นตรวจสอบแอตทริบิวต์ของอินสแตนซ์นั้นพบว่าเป็นอินสแตนซ์เก่าของกิจกรรมไม่ใช่กิจกรรมที่กำลังทำงานอยู่ในปัจจุบัน [ยิ่งไปกว่านั้นฉันใช้ socket.io และฉันลืมทำ socket.off ("ตัวอย่าง", ตัวอย่าง) ... ดังนั้นมันจึงแนบกับอินสแตนซ์เก่าของกิจกรรม ]

  • ในส่วนที่สอง: ฉันพยายามแสดง DialogFragment ในกิจกรรมเมื่อฉันกลับมาที่มันด้วยความตั้งใจ แต่เมื่อฉันตรวจสอบบันทึกของฉันฉันเห็นว่าเมื่อมันพยายามที่จะแสดงส่วนย่อยกิจกรรมก็ยังไม่อยู่ในเมธอด onStart ดังนั้นแอปจึงขัดข้องเนื่องจากไม่พบชั้นกิจกรรมที่จะแสดงส่วนย่อย

เคล็ดลับบางประการ: ตรวจสอบแอตทริบิวต์บางอย่างหากคุณไม่ได้ใช้อินสแตนซ์เก่าของกิจกรรมที่คุณพยายามแสดงส่วนของคุณหรือตรวจสอบวงจรกิจกรรมของคุณก่อนที่จะแสดงส่วนของคุณและตรวจสอบว่าคุณอยู่ใน onStart หรือ onResume ก่อนที่จะแสดง .

ฉันหวังว่าคำอธิบายเหล่านั้นจะช่วยคุณได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.