Gab*_*abi 11 android android-fragments kotlin back-stack fragmentmanager
我在MainActivity中使用底部导航栏来处理一些片段。这是用于在它们之间切换的代码:
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
if (item.isChecked &&
supportFragmentManager.findFragmentById(R.id.act_main_fragment_container) != null
)
return@OnNavigationItemSelectedListener false
val fragment =
when (item.itemId) {
R.id.navigation_home -> fragments[0]
R.id.navigation_bookings -> fragments[1]
R.id.navigation_messages -> fragments[2]
R.id.navigation_dashboard -> fragments[3]
R.id.navigation_profile -> fragments[4]
else -> fragments[0]
}
this replaceWithNoBackStack fragment
return@OnNavigationItemSelectedListener true
}
Run Code Online (Sandbox Code Playgroud)
方法replaceWithNoBackstack只是此的简写:
supportFragmentManager
?.beginTransaction()
?.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
?.replace(containerId, fragment)
?.commit()
Run Code Online (Sandbox Code Playgroud)
问题是,当我在它们之间更快地切换时,我的应用程序崩溃,但出现以下异常:
java.lang.IllegalStateException:仅在所有者的初始化阶段,必须在androidx的androidx.fragment.app.Fragment.performCreate(Fragment.java:2580)的androidx.savedstate.SavedStateRegistryController.performRestore(SavedStateRegistryController.java:59)上创建重新启动器。 androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1237)处于androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1302)处的fragment.app.FragmentManagerManager.mpl.moveToState(FragmentManagerImpl.java:837) androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2075)上的.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439),位于androidx.fragment.app.FragmentManagerImpl。在androidx.fragment.app上的executeOpsTogether(FragmentManagerImpl.java:1865)在androidx.fragment.app处的FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1820)在androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1726)在androidx.fragment。 $ 2.run(FragmentManagerImpl.java:150)在android.os.Handler.handleCallback(Handler.java:789)在android.os.Handler.dispatchMessage(Handler.java:98)在android.os.Looper.loop(Looper .java:164),位于android.app.ActivityThread.main(ActivityThread.java:6709),位于com.android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote)的java.lang.reflect.Method.invoke(本机方法) .java:240),位于com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769),我是我已经搜索了很多,却找不到答案。
如果我进行API调用,将应用程序置于后台,等待响应,并且在我返回到应用程序时,由于我试图立即显示对话框片段而导致应用程序崩溃,我也会遇到此错误(原因是我认为这是因为在显示对话框片段时,从后台返回时重新创建片段的事务仍在进行中。我通过设置对话框的500ms延迟来解决此问题,因为我找不到其他解决方案。
请询问您是否需要有关此的更多详细信息。先感谢您!
可能的温度解决方案
编辑
我通过将应用程序兼容性降低到了androidx.appcompat:appcompat:1.0.2这个级别来解决了这个问题,但这只是一个临时解决方案,因为我将来必须对其进行更新。我希望有人能解决。
编辑2 我通过从片段事务中删除setTransition()解决了该问题。至少我知道android应用总体上没有良好过渡的原因
编辑3 也许是避免此问题并让事情顺利进行的最佳解决方案,只是使用ViewPager处理底部栏导航
因为1.0.0版本没有检查状态,所以不会抛出异常,但是1.1.0版本改变了源代码,所以抛出异常。
这是Fragment version-1.1.0 源代码,它将调用该方法performRestore
void performCreate(Bundle savedInstanceState) {
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
}
mState = CREATED;
mCalled = false;
mSavedStateRegistryController.performRestore(savedInstanceState);
onCreate(savedInstanceState);
mIsCreated = true;
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onCreate()");
}
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}
/**
the exception
**/
public void performRestore(@Nullable Bundle savedState) {
Lifecycle lifecycle = mOwner.getLifecycle();
if (lifecycle.getCurrentState() != Lifecycle.State.INITIALIZED) {
throw new IllegalStateException("Restarter must be created only during "
+ "owner's initialization stage");
}
lifecycle.addObserver(new Recreator(mOwner));
mRegistry.performRestore(lifecycle, savedState);
}
Run Code Online (Sandbox Code Playgroud)
这是1.0.0版本的源代码?没有调用performRestore,所以不会抛出异常
void performCreate(Bundle savedInstanceState) {
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
}
mState = CREATED;
mCalled = false;
onCreate(savedInstanceState);
mIsCreated = true;
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onCreate()");
}
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}
Run Code Online (Sandbox Code Playgroud)
有两种不同的解决方案可以处理这个问题:
第一个解决方案是拆分事务?
因为我们总是使用replace或合并remove,并add到一个事务。我们可以像这样将事务拆分为两个事务:
FragmentTransaction ft = manager.beginTransaction();
Fragment prev = manager.findFragmentByTag(tag);
if (prev != null) {
//commit immediately
ft.remove(prev).commitAllowingStateLoss();
}
FragmentTransaction addTransaction = manager.beginTransaction();
addTransaction.addToBackStack(null);
addTransaction.add(layoutId, fragment,
tag).commitAllowingStateLoss();
Run Code Online (Sandbox Code Playgroud)
因为这两个事务将是两个不同的 Message 将由 Handler 处理。
第二种解决方案是提前检查状态。我们可以按照源代码?提前检查状态
FragmentTransaction ft = manager.beginTransaction();
Fragment prev = manager.findFragmentByTag(tag);
if (prev != null) {
if (prev.getLifecycle().getCurrentState() != Lifecycle.State.INITIALIZED) {
return;
}
ft.remove(prev);
}
Run Code Online (Sandbox Code Playgroud)
我推荐第一种方式,因为第二种方式是跟着源码走的,如果源码改了代码,会失效吗?
小智 5
我有同样的问题。
val fragment = Account.activityAfterLogin
val ft = activity?.getSupportFragmentManager()?.beginTransaction()
//error
ft?.setCustomAnimations(android.R.anim.slide_in_left,android.R.anim.slide_out_right)0
ft?.replace(R.id.framelayout_account,fragment)
ft?.commit()
Run Code Online (Sandbox Code Playgroud)
更改库版本没有帮助。我通过ft?.AddToBackStack(null)在ft?.setCustomAnimations ()方法之后添加一行来解决这个问题,就是这样。动画有效,没有崩溃。
如果您使用的是“androidx.core:core-ktx:1.0.2”,请尝试更改为 1.0.1
如果您使用生命周期(或 rxFragment)和 androidx_appcompat:alpha05,请尝试更改版本。
例如)应用程序兼容性:1.1.0-beta01 或 1.0.2
我认为当重用目标片段(onPause-onResume)时保存状态时,它会显示为错误。
| 归档时间: |
|
| 查看次数: |
2036 次 |
| 最近记录: |