非法状态异常:无法在 onSaveInstanceState 后执行此操作 - Android

3

我试图弄清楚为什么我的安卓应用程序有时会崩溃,并显示上述异常。从logcat中无法找到问题的来源。

这种情况很少发生。

Logcat输出:

java.lang.IllegalStateException: 保存实例状态后不能执行此操作,位于 android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1360) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1378) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574) at android.support.v4.app.FragmentTabHost.onAttachedToWindow(FragmentTabHost.java:282) at android.view.View.dispatchAttachedToWindow(View.java:12752) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2577) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2584) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2584) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2584) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1427) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1192) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6231) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788) at android.view.Choreographer.doCallbacks(Choreographer.java:591) at android.view.Choreographer.doFrame(Choreographer.java:560) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774) at android.os.Handler.handleCallback(Handler.java:808) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:5292) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640) at dalvik.system.NativeStart.main(Native Method)

主要活动:

public class MainActivity extends FragmentActivity {

    private FragmentTabHost mTabHost;    
    private UiLifecycleHelper uiHelper;

    LocationClient mClient;
    LocationRequest mRequest;
    private String user;
    private String userId;
    private ImageButton addPlaceBtn;
    private SQLiteDataSource datasource;
    private TextView notifTextView;
    private boolean appIsOn = false; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActionBar actionBar = getActionBar();
        actionBar.setDisplayShowHomeEnabled(true);
        actionBar.setDisplayShowTitleEnabled(false);
        setContentView(R.layout.activity_main);

        datasource = new SQLiteDataSource(this);
        datasource.open();

        uiHelper = new UiLifecycleHelper(this, null);
        uiHelper.onCreate(savedInstanceState);

        if (isFacebookLoggedIn()) {
            System.out.println("We are logged in!");
        } else {
            showLogin();
        }

        if (datasource.getAllImageItems().isEmpty()) {
            Intent splash = new Intent(this, SplashActivity.class);
            startActivity(splash);
        }

        addPlaceBtn = (ImageButton) findViewById(R.id.addPlace1);

        uiHelper = new UiLifecycleHelper(this, null);
        uiHelper.onCreate(savedInstanceState);

        mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(),
                android.R.id.tabcontent);

        mTabHost.addTab(
                mTabHost.newTabSpec("tab1").setIndicator("PREPARATE", null),
                OffersFragmentActivity.class, null);
        mTabHost.addTab(
                mTabHost.newTabSpec("tab2").setIndicator("CATEGORII", null),
                CategoriesActivity.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("tab3")
                .setIndicator("CAIETE", null), BooksFragmentActivity.class,
                null);

        for (int i = 0; i < mTabHost.getTabWidget().getChildCount(); i++) {
            mTabHost.getTabWidget().getChildAt(i)
                    .setBackgroundResource(R.drawable.tab_text_selector);
            mTabHost.getTabWidget().setDividerDrawable(R.drawable.divider);
            final TextView tv = (TextView) mTabHost.getTabWidget()
                    .getChildAt(i).findViewById(android.R.id.title);
            if (tv == null)
                continue;
            else
                tv.setTextColor(0xFFFFFFFF);
        }

        mTabHost.setOnTabChangedListener(new OnTabChangeListener() {

            public void onTabChanged(String tabId) {

                switch (mTabHost.getCurrentTab()) {
                case 0:
                    addPlaceBtn.setVisibility(View.VISIBLE);
                    break;
                case 1:
                    addPlaceBtn.setVisibility(View.GONE);
                    break;
                case 2:
                    addPlaceBtn.setVisibility(View.GONE);
                    break;

                default:

                    break;
                }
            }
        });

        addPlaceBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (user != null && isOnline()) {
                    Intent i = new Intent(getApplication(),
                            CameraActivity.class);
                    startActivity(i);
                } else if (user == null) {
                    // If user is not logged in, start login activity
                    Intent i = new Intent(getApplication(), LoginActivity.class);
                    startActivity(i);
                } else if (!isOnline()) {
                    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
                            MainActivity.this);
                    alertDialogBuilder.setTitle("Internetul este oprit");
                    alertDialogBuilder
                            .setMessage("Pentru actualizarea continutului aveti nevoie de internet. Porniti acum?");
                    alertDialogBuilder.setPositiveButton("Da",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    // go to a new activity of the app
                                    Intent settingsIntent = new Intent(
                                            Settings.ACTION_DATA_ROAMING_SETTINGS);
                                    settingsIntent
                                            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                    startActivity(settingsIntent);
                                    finish();
                                }
                            });
                    // set negative button: No message
                    alertDialogBuilder.setNegativeButton("Nu",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog,
                                        int id) {
                                    // cancel the alert box and put a Toast to
                                    // the user
                                    finish();
                                }
                            });

                    AlertDialog alertDialog = alertDialogBuilder.create();
                    alertDialog.show();
                }
            }
        });

        if(!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
            Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(this));
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);        
        // Associate searchable configuration with the SearchView
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.search)
                .getActionView();
        searchView.setSearchableInfo(searchManager
                .getSearchableInfo(getComponentName()));

        final Menu m = menu;
        final MenuItem item = menu.findItem(R.id.action_notifications);
        View actionView = item.getActionView();
        notifTextView = (TextView) actionView.findViewById(R.id.notifTextView);

        String unreadNotifs = datasource.countUnreadNotif();
        if (!unreadNotifs.equals("0")) {
            notifTextView.setText(unreadNotifs);
        } else {
            notifTextView.setVisibility(View.GONE);
        }

        item.getActionView().setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                m.performIdentifierAction(item.getItemId(), 0);

            }
        });

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_user) {
            Intent i = new Intent(this, UserProfile.class);
            i.putExtra("user", user);
            i.putExtra("userId", userId);
            startActivity(i);

            return true;
        }

        if (id == R.id.action_notifications) {
            Intent i = new Intent(this, Notifications.class);
            startActivity(i);

            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private boolean isFacebookLoggedIn() {
        Session session = Session.getActiveSession();

        if (session != null) {
            // Session can be open, check for valid token
            if (!session.isClosed()) {
                if (!session.getAccessToken().equalsIgnoreCase("")) {
                    return true;
                }
            }
        }
        return false;
    }

    // FB Login Session and user info
    public void showLogin() {
        Intent i = new Intent(this, LoginActivity.class);
        startActivity(i);

    }

    @Override
    protected void onResume() {
        super.onResume();
        uiHelper.onResume();
        appIsOn = true;
        invalidateOptionsMenu();

        if (!isOnline()) {
            showGpsButton();
        }

        SharedPreferences preferences = getSharedPreferences("USERINFO",
                Context.MODE_PRIVATE);
        user = preferences.getString("name", null);
        userId = preferences.getString("userId", null);
        userId = preferences.getString("userId", null);

        GCMActivity gcm = new GCMActivity(this);
        gcm.registerIfNeeded();

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        uiHelper.onSaveInstanceState(outState);
    }

    @Override
    public void onPause() {
        super.onPause();
        uiHelper.onPause();
        appIsOn = false;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        uiHelper.onDestroy();
        datasource.deleteAllRows();

    }

    public void showGpsButton() {
        LinearLayout buttonLayout = (LinearLayout) findViewById(R.id.gpsWarning);
        buttonLayout.setVisibility(View.VISIBLE);
        buttonLayout.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Intent settingsIntent = new Intent(
                        Settings.ACTION_DATA_ROAMING_SETTINGS);
                settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(settingsIntent);
                finish();
            }
        });
    }

    public boolean isOnline() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo = cm.getActiveNetworkInfo();
        if (netInfo != null && netInfo.isConnected()) {
            return true;
        }
        return false;
    }
}

在使用片段时,请使用.commitAllowingStateLoss()而不是Commit()。 - Ganesh AB
我进行了一些研究,阅读了其他帖子以及@Alex Lockwood在这个主题上的博客文章。但是我的活动中只有一个Fragment TabHost,并且我从未调用“commit()”。通常,如果我的应用程序中有任何崩溃,我会在另一个崩溃之后立即收到此错误。 - Edmond Tamas
如果您没有调用commit(),那么框架肯定会调用。证据在于堆栈跟踪:android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)BackStackRecord是框架对抽象的FragmentTransaction类的内部实现)。 - Alex Lockwood
@AlexLockwood 感谢您的支持。您认为有什么方法可以解决这个问题吗?我能否以某种方式覆盖此行为? - Edmond Tamas
显示剩余2条评论
1个回答

1
我在KitKat上遇到了类似的问题。但在Lollipop上似乎可以正常工作。无论如何,我们必须支持许多操作系统版本,对吧?:)
主要原因似乎是启动新活动会在它完全创建完成之前强制暂停MainActivity。当它暂停时,它立即保存实例状态。但由于Fragment实例在奇怪的主线程结束周期中被提交,这种开始-暂停-保存周期变得无序,导致崩溃。在某些情况下,这可能是竞争条件,会间歇性发生。
以下是经过反复测试后似乎可以解决问题的一些代码:
@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);

    Handler hanlder = new Handler();
    hanlder.post(new Runnable() {
        @Override
        public void run() {
            if (isFacebookLoggedIn()) {
                System.out.println("We are logged in!");
            } else {
                showLogin();
            }

            if (datasource.getAllImageItems().isEmpty()) {
                Intent splash = new Intent(MainActivity.this, SplashActivity.class);
                startActivity(splash);
            }
        }
    });
}

关键在于生成一个Handler,并在主线程的末尾发布以确保它发生在所有Fragment实例被提交之后。在onCreate中立即执行会导致问题,因此在onPostCreate中执行应该有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接