java.lang.IllegalStateException: Không thể thực hiện hành động này sau khi onSaveInstanceState


135

Tôi đang sử dụng thư viện hỗ trợ cho ứng dụng của mình. Trong FragmentActivity của tôi, tôi đang sử dụng AsyncTask để tải xuống dữ liệu từ internet. Trong phương thức onPreExecute () tôi thêm một đoạn và trong phương thức onPostExecute () tôi xóa nó một lần nữa. Khi định hướng được thay đổi ở giữa, tôi nhận được ngoại lệ được đề cập ở trên. Xin hãy xem chi tiết:

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

Tôi nhận được sau 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)

Trong các luồng khác về các vấn đề tương tự, lý do dường như là phương thức onPostExecute được gọi trước khi phương thức onResume () được gọi. Nhưng tôi nhận được ngoại lệ mặc dù onResume () được gọi trước đó.

Có ai biết những gì sai?

Hoạt động trông như thế này:

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

Khi sử dụng commit ALLowingStateLoss () tôi nhận được ngoại lệ sau:

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)

Tôi nhận được cùng một IllegalStateExellect khi tôi triển khai AsynTask như sau, bởi vì phương thức findFragmentById () trả về một con trỏ 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();
    }

Trong bước tiếp theo, tôi sử dụng một trình xử lý để thêm và xóa DummyFragment. Ngoài ra, tôi đã thêm một số đầu ra gỡ lỗi.

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

Tôi nhận được sau 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)

Trong onPreExecute () FriendListFragment có id = 0x7f0a0002. Bên trong trình xử lý, DummyFragment được tạo với id = 0x7f0a0004. Trong onPostExecute () cả hai ID đều null. Trong onPreExecute () địa chỉ của MyFragmentActivity là 45e38353. nhưng trong onPostExecute () thì không. Nhưng trong cả hai phương thức, địa chỉ FragmentManager là 45e384a8. Tôi đoán onPostExecute sử dụng FragmentManager không hợp lệ. Nhưng tại sao?


1
Tôi đã gặp vấn đề này một lần và khắc phục nó bằng cách thay thế cam kết bằng điều này: commit ALLowingStateLoss (), bạn có thể thử điều này không?
Cata

Tôi đã thử điều này, nhưng không thành công. Theo LogCat, Fragment phải ở trạng thái phù hợp.
samo

Bạn có thể vui lòng gửi mã Hoạt động của bạn?
Robert Estivill

Khi tôi sử dụng commit ALLowingStateLoss () tôi nhận được một ngoại lệ khác (xem bên trên).
samo

6
Đối với những người bạn vẫn đang tìm kiếm một giải pháp ... hãy xem bài đăng trên blog về chủ đề này để biết thêm thông tin.
Alex Lockwood

Câu trả lời:


97

Bạn nên thực hiện giao dịch trong một Handler như sau:

@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
Nó không giúp được gì. Hành vi cũng giống như trước đây.
samo

@samo xin vui lòng bạn đã có thể giải quyết vấn đề? Tôi có một liên kết
Lisa Anne

3
Xem xét mã này:private static WeakReference<FragmentActivity> mActivity = null;
Oleg Vaskevich

2
Tóm lại, WeakReferencengăn bạn rò rỉ hoạt động ... bạn cần gọi mActivity.get()để thực sự lấy ví dụ và nó sẽ bị vô hiệu nếu hoạt động bị hủy. Để cập nhật nó, bạn sẽ cần phải viết mActivity = new WeakReference<FragmentActivity>(this);- một vị trí tốt đang ở onCreate()- nơi sẽ cập nhật tài liệu tham khảo.
Oleg Vaskevich

107
Đối với những người bạn vẫn đang tìm kiếm một giải pháp ... hãy xem bài đăng trên blog về chủ đề này để biết thêm thông tin.
Alex Lockwood

55

Cảm ơn Oleg Vaskevich. Sử dụng một WeakReferencetrong FragmentActivitynhững vấn đề được giải quyết. Mã của tôi trông như sau:

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

ý tưởng tham khảo yếu thực sự là một ý tưởng rất thông minh, điều này sẽ cho phép đối tượng dễ dàng thu gom rác khi cần thiết. giơ ngón tay cái lên samo!
Jimmy Ilenloa

Tại sao tĩnh được sử dụng ở đây? Điều gì sẽ xảy ra nếu tôi sử dụng MyFragmentActivity mActivity = this ?With out static & WeakReference
Bharath

Tham chiếu tĩnh là kỹ thuật khá tệ, bạn nên gắn asynchtask của mình vào vòng đời và hủy khi cần thiết
vỡ

38

Tôi tin rằng câu trả lời chính xác cho câu hỏi này là phương pháp sau đây.

public abstract int commitAllowingStateLoss ()

Giống như commit () nhưng cho phép thực hiện cam kết sau khi trạng thái của một hoạt động được lưu. Điều này rất nguy hiểm vì cam kết có thể bị mất nếu sau đó hoạt động cần được khôi phục từ trạng thái của nó, do đó, điều này chỉ nên được sử dụng cho các trường hợp trạng thái UI thay đổi bất ngờ đối với người dùng.

Mô tả ở trên liên quan đến phương pháp này.

protected void onSaveInstanceState(android.os.Bundle outState)

Vấn đề này xảy ra chính xác khi thiết bị đi ngủ.

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


25

Giải pháp ngắn gọn và hiệu quả:

Thực hiện theo các bước đơn giản:

Bước 1 : Ghi đè onSaveInstanceStatetrạng thái trong đoạn tương ứng. Và loại bỏ siêu phương pháp từ nó.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Bước 2 : Sử dụng CommitAllowingStateLoss();thay vì commit();trong khi hoạt động phân mảnh.

fragmentTransaction.commitAllowingStateLoss();

2
Cảm ơn. Điều này làm việc cho tôi, nhưng tôi biết đó không phải là giải pháp tốt nhất.
wendigo

2
loại bỏ siêu phương thức, cũng vô hiệu hóa lưu trạng thái mảnh của bạn.
Juan Mendez

1
Cảm ơn rất nhiều. Nó đã tạo ra một ngoại lệ, giải pháp này hoạt động tốt ..
Deepak

11

Kiểm tra nếu các hoạt động isFinishing()trước khi hiển thị các mảnh.

Thí dụ:

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

5

Tôi đã có một vấn đề tương tự mà tôi cố định bằng cách di chuyển một số mã giao dịch đoạn từ onResume()thànhonStart() .

Nói chính xác hơn: Ứng dụng của tôi là một trình khởi chạy. Sau khi nhấn nút Trang chủ Android, người dùng có thể chọn trình khởi chạy cho đến khi quyết định của mình được ghi nhớ. Khi đi "trở lại" tại thời điểm này (ví dụ: bằng cách chạm vào vùng màu xám), ứng dụng đã bị sập.

Có lẽ điều này giúp ai đó.


4

Sử dụng commitAllowingStateLoss()thay vì commit() .

Khi bạn sử dụng, commit()nó sẽ có thể ném ngoại lệ nếu mất trạng thái xảy ra nhưng commitAllowingStateLoss()lưu giao dịch mà không mất trạng thái do đó sẽ không ném ngoại lệ nếu mất trạng thái.


2

Điều đó đã xảy ra với tôi, bởi vì tôi đang viện dẫn commit()từ hoạt động phụ đang bị rò rỉ hoạt động. Nó giữ hoạt động như một tài sản và trên một biến hoạt động xoay vòng không được cập nhật bởi onAttach();vì vậy tôi đã cố gắng thực hiện giao dịch trên zombie Hoạt động bằng cách giữ lại (setRetainInstance(true);)đoạn.


2

Lý do cho ngoại lệ là việc tạo lại FragmentActivitytrong thời gian chạy của AsyncTaskvà truy cập vào trước đó, bị phá hủy FragmentActivitytrongonPostExecute() sau đó.

Vấn đề là để có được một tài liệu tham khảo hợp lệ cho cái mới FragmentActivity. Không có phương pháp nào cho điều này getActivity()cũng không findById()hoặc một cái gì đó tương tự. Diễn đàn này có đầy đủ các chủ đề theo vấn đề này (ví dụ: tìm kiếm"Activity context in onPostExecute" ). Một số trong số họ đang mô tả cách giải quyết (cho đến bây giờ tôi đã không tìm thấy một cách tốt).

Có lẽ nó sẽ là một giải pháp tốt hơn để sử dụng Dịch vụ cho mục đích của tôi.


2

Có một giải pháp thay thế (KHÔNG phải là giải pháp tốt nhất) cho vấn đề này, nhưng hoạt động. Sử dụng cờ bạn có thể xử lý nó, như dưới đây

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

Và bạn có thể kiểm tra booleangiá trị này trong khi thực hiện giao dịch mảnh.

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

1

Cho những gì nó có giá trị; Tôi gặp lỗi này trên một ứng dụng đang chạy các dịch vụ trong nền. Trên một trong số đó, một hộp thoại hết thời gian phải được hiển thị cho người dùng. Hộp thoại đó là vấn đề gây ra lỗi này nếu ứng dụng không còn chạy ở nền trước.

Trong trường hợp của chúng tôi, hộp thoại hiển thị không hữu ích khi ứng dụng ở chế độ nền nên chúng tôi chỉ theo dõi điều đó (boolean được gắn cờ onPause en onResume) và sau đó chỉ hiển thị hộp thoại khi ứng dụng thực sự hiển thị cho người dùng.


1

Giải pháp 1: ghi đè onSaveInstanceState()và loại bỏ siêu cuộc gọi trong đó.

@Override
public void onSaveInstanceState(Bundle outState) {
}

Giải pháp 2: ghi đè onSaveInstanceState()và xóa đoạn của bạn trước siêu cuộc gọi

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

1

Vấn đề này xảy ra khi một quá trình cố gắng thao túng một Hoạt động onStop()đã được gọi. Nó không nhất thiết phải gắn với giao dịch phân mảnh mà còn các phương thức khác như onBackPression ().

Ngoài AsyncTask, một nguồn khác của vấn đề như vậy là việc đặt sai vị trí đăng ký của mẫu xe buýt. Thông thường, thuê bao của Event Bus hoặc RxBus được đăng ký trong OnCreate của Activity và hủy đăng ký trong onDestroy. Nếu một Hoạt động mới bắt đầu và xuất bản một sự kiện bị chặn bởi những người đăng ký từ Hoạt động trước đó thì nó có thể gây ra lỗi này. Nếu điều này xảy ra thì một giải pháp là chuyển đăng ký đăng ký và hủy đăng ký sang onStart()onStop().


1

Điều này đã giải quyết vấn đề của tôi: Mã Kotlin:

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

Làm thế nào là commitAllowingStateLoss()khác nhau hơn commit()?

Theo tài liệu:

Thích commit()nhưng cho phép cam kết được thực thi sau khi trạng thái của một hoạt động được lưu. https://developer.android.com/reference/android/app/FragmentTransaction#commit ALLowingStateLoss ()

PS: bạn có thể hiển thị Hộp thoại Mảnh vỡ hoặc có thể tải các đoạn bằng phương pháp này. Áp dụng cho cả hai.


0

Ứng dụng của tôi có một đoạn để tải trong 3 giây, nhưng khi màn hình nắm tay chuẩn bị hiển thị, tôi nhấn nút home và tiếp tục chạy nó, nó hiển thị cùng một lỗi, vì vậy Nó chỉnh sửa mã của tôi và nó chạy rất mượt:

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

LƯU Ý: thêm commit ALLowingStateLoss () thay vì commit ()


0

Bắt đầu từ thư viện hỗ trợ phiên bản 24.0.0, bạn có thể gọi FragmentTransaction.commitNow()phương thức cam kết giao dịch này một cách đồng bộ thay vì gọi commit()theo sauexecutePendingTransactions()


0

IllegalStateException gặp phải nếu bạn thực hiện bất kỳ giao dịch phân đoạn nào sau khi hoạt động bị mất trạng thái - Hoạt động không ở phía trước. Điều này thường gặp khi bạn cố gắng thực hiện bất kỳ phân đoạn nào trong AsyncTask hoặc sau khi yêu cầu mạng.

Để tránh sự cố này, bạn chỉ cần trì hoãn bất kỳ giao dịch phân đoạn nào cho đến khi trạng thái hoạt động được khôi phục. Sau đây là cách nó được thực hiện

Khai báo hai biến boolean riêng

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;

Bây giờ, trong onPostResume () và onPause, chúng tôi đã đặt và hủy đặt biến boolean của chúng tôi làTransactionSafe. Ý tưởng là chỉ đánh dấu sự vận chuyển an toàn khi hoạt động ở phía trước để không có cơ hội 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();
    }
}

Những gì chúng tôi đã làm cho đến nay sẽ tiết kiệm được từ IllegalStateException nhưng các giao dịch của chúng tôi sẽ bị mất nếu chúng được thực hiện sau khi hoạt động chuyển sang nền, giống như commit ALLowStateloss (). Để giúp với điều đó, chúng ta có biến 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;
 }
}

Bài viết này giải thích khá chi tiết về lý do tại sao ngoại lệ này gặp phải và so sánh các phương pháp khác nhau để giải quyết nó. Rất khuyến khích


0

Tôi có cùng một ngoại lệ và tôi đã thử nhiều đoạn mà tôi tìm thấy ở đây trong cuộc thảo luận về stackoverflow này, nhưng không có đoạn nào làm việc cho tôi.

Nhưng tôi đã có thể giải quyết tất cả các vấn đề, tôi sẽ chia sẻ với bạn các giải pháp:

  • Trong phần đầu tiên: tôi đã cố gắng hiển thị DialogFragment trên một Activity nhưng từ một lớp java khác. Sau đó, bằng cách kiểm tra thuộc tính của cá thể đó, tôi thấy đó là một phiên bản cũ của Hoạt động, nó không phải là Hoạt động đang chạy hiện tại. [Chính xác hơn là tôi đang sử dụng socket.io và tôi đã quên thực hiện một socket.off ("ví dụ", ví dụ) ... vì vậy nó gắn liền với một ví dụ cũ của hoạt động. ]

  • Trong phần thứ hai: Tôi đã cố gắng hiển thị DialogFragment trong một Hoạt động khi tôi quay lại với ý định đó, nhưng khi tôi kiểm tra nhật ký của mình, tôi thấy rằng khi nó cố gắng hiển thị đoạn đó thì hoạt động vẫn không ở phương thức onStart , do đó, nó đã đánh sập ứng dụng vì nó không tìm thấy lớp Activity để hiển thị đoạn trên đó.

Một số mẹo: kiểm tra với một số thuộc tính nếu bạn không sử dụng phiên bản cũ của hoạt động mà bạn đang cố gắng hiển thị đoạn của mình hoặc kiểm tra vòng đời hoạt động của bạn trước khi hiển thị đoạn của bạn và chắc chắn rằng bạn đang ở trong OnStart hoặc onResume trước khi hiển thị nó .

Tôi hy vọng những lời giải thích sẽ giúp bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.