java - FragmentTransaction 仅在纵向模式下工作

标签 java android android-fragments android-appcompat

我的 Android 代码有一个非常奇怪的行为。

真正的问题在代码之后。

我想要做的是拥有一个应用程序,该应用程序只能在手机上以纵向模式运行,而在平板电脑上可以同时以纵向和横向模式运行。为此,我在不同的文件夹中创建了三个 bool.xml 文件。这个在文件夹值中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">true</bool>
</resources>

我在 values-xlarge 和 values-sw600dp 中放置

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="portrait_only">false</bool>
</resources>

项目中唯一的 Activity 加载,在启动时通过附加 SplashScreenFragment 启动一个启动画面。这是 Activity

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getResources().getBoolean(R.bool.portrait_only)) 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    if (getSupportActionBar() != null)
        getSupportActionBar().hide();
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
        .add(R.id.container, new SplashScreenFragment()).commit();
    }
}
}

fragment 本身只是加载一个布局并启动一个 TimerTask 来改变 fragment 。在这里

public class SplashScreenFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_splash_screen, container, false);

        Timer splashScreenTimer = new Timer();
        splashScreenTimer.schedule(new SplashScreenTimerTask(getActivity()), 2000);

        return rootView;
    }

    private class SplashScreenTimerTask extends TimerTask {
        private FragmentActivity activity;

        public SplashScreenTimerTask(FragmentActivity activity) {
            this.activity = activity;
        }

        @Override
        public void run() {
            FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.container, new FragmentMain());
            transaction.commit();
        }

    }

}

现在,如果我在手机上以纵向模式启动应用程序,一切都完美无缺,而如果我以横向模式在手机上启动应用程序,那么第一个 fragment 会完美加载,但是当行

transaction.commit();

被执行,应用程序崩溃并在 logcat 中显示以下错误

E/AndroidRuntime(17433): FATAL EXCEPTION: Timer-0
E/AndroidRuntime(17433): Process: it.assottica.android, PID: 17433
E/AndroidRuntime(17433): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
E/AndroidRuntime(17433):    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1354)
E/AndroidRuntime(17433):    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1372)
E/AndroidRuntime(17433):    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
E/AndroidRuntime(17433):    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
E/AndroidRuntime(17433):    at it.assottica.android.fragments.SplashScreenFragment$SplashScreenTimerTask.run(SplashScreenFragment.java:40)
E/AndroidRuntime(17433):    at java.util.Timer$TimerImpl.run(Timer.java:284)

有人知道为什么会发生这种情况以及如何解决吗?但是,最重要的是,如果我在横向或纵向模式下使用移动设备启动应用程序,为什么一切正常?

最佳答案


我通过深入跟踪 Activity 和 Fragment 中的 onPause 和 onStop 中实际执行了哪些方法解决了我自己的问题。

和我想的不一样的是,当我在横向模式下用手机启动orientation时,Activity和Fragment经历了以下过程:onCreateView -> onPause -> onStop -> onDestroy -> onCreateView,这正是当您以某个方向启动 Activity 然后更改屏幕方向时,会发生相同的过程。这导致了Fragment被启动,然后被销毁,然后被重启,所以第一次启动时创建的定时器,试图在执行onSaveInstanceState之后,去获取一个实际上不存在的activity的支持fragment manager或者执行一个事务。

我通过在 Fragment 的 onDestroy() 方法中取消计时器来解决。

关于java - FragmentTransaction 仅在纵向模式下工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24699198/

相关文章:

java - 是否可以在java流中使用when()初始化模拟

java - 在 Hibernate 集合和我自己的集合之间转换

android - 如何修改芯片的样式?

android - ScaleGestureDetector 不适用于 ICS 及以下的 Fragment 或 ViewGroup 布局中的 View

java - 使用 Guice 为参数注释编写拦截器

java - 如何从嵌套的 HashMap 中检索键而不是其值

Android "hello world"- 版本

android - 如何在 Android 手机中制作我自己的自定义拨号器

java - 抽象类和多态问题

屏幕方向更改后以错误的顺序添加了 Android fragment