我的 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/