gpt4 book ai didi

android - 后台管理 : Restarter must be created only during owner's initialization stage

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:20:33 35 4
gpt4 key购买 nike

我在 MainActivity 中使用底部导航栏来处理一些 fragment 。这是用于在它们之间切换的代码:

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
}

方法 replaceWithNoBackstack 只是一个简写:

supportFragmentManager
?.beginTransaction()
?.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
?.replace(containerId, fragment)
?.commit()

问题是当我在它们之间切换得更快时,我的应用程序崩溃并出现以下异常:

java.lang.IllegalStateException: Restarter must be created only during owner's initialization stage at androidx.savedstate.SavedStateRegistryController.performRestore(SavedStateRegistryController.java:59) at androidx.fragment.app.Fragment.performCreate(Fragment.java:2580) at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:837) at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1237) at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1302) at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439) at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2075) at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1865) at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1820) at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1726) at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150) at android.os.Handler.handleCallback(Handler.java:789) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6709) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769) I've been searching a lot and couldn't find an answer.

如果我执行 API 调用,将应用程序置于后台,等待响应,当我返回应用程序时,应用程序崩溃,因为我试图立即显示对话框 fragment ,我也会遇到此错误(我认为发生这种情况的原因是从后台返回时重新创建 fragment 的事务在显示对话框 fragment 时仍在进行中)。我通过为对话框设置 500 毫秒的延迟以一种 hacky 的方式解决了这个问题,因为我想不出其他解决方案。

请询问您是否需要有关此的更多详细信息。提前致谢!

可能的临时解决方案

编辑我通过将应用程序兼容性依赖项降级为 androidx.appcompat:appcompat:1.0.2 解决了这个问题,但这只是一个临时解决方案,因为我将来必须更新它。我希望有人能解决这个问题。

编辑 2我通过从 fragment 事务中删除 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);
}

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

两种不同的解决方案可以解决这个问题:
第一个解决方案是拆分事务。
因为我们总是使用replace或者将removeadd合并到一个Transaction中。我们可以像这样将事务拆分为两个事务:

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

因为这两个事务将是两个不同的消息,将由 Handler 处理。
第二种解决方案是提前检查状态。我们可以按照源码,提前查看状态

FragmentTransaction ft = manager.beginTransaction();
Fragment prev = manager.findFragmentByTag(tag);
if (prev != null) {
if (prev.getLifecycle().getCurrentState() != Lifecycle.State.INITIALIZED) {
return;
}
ft.remove(prev);
}

我推荐第一种方式,因为第二种方式是跟着源码走,如果源码代码更改代码,将无效。

关于android - 后台管理 : Restarter must be created only during owner's initialization stage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56539251/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com