背景
Android 中的异步回调
尝试在 Android 上以可靠的方式执行异步操作是不必要的复杂,即AsyncTask 是否真的在概念上存在缺陷,或者我只是错过了什么?
现在,这一切都发生在 Fragments 引入之前。随着 Fragments 的引入,onRetainNonConfigurationInstance()已被弃用。所以最新的谷歌纵容黑客是使用一个持久的非 UI 片段,当配置更改发生时(即旋转屏幕、更改语言设置等)从你的 Activity 附加/分离。
示例: https ://code.google.com/p/android/issues/detail?id=23096#c4
IllegalStateException - 在 onSaveInstanceState 之后无法执行此操作
从理论上讲,上面的 hack 可以让你绕过可怕的:
IllegalStateException - "Can not perform this action after onSaveInstanceState"
因为持久的非 UI 片段将接收 onViewStateRestored()(或者 onResume)和 onSaveInstanceState()(或者 onPause)的回调。因此,您可以知道何时保存/恢复实例状态。对于如此简单的事情,这是相当多的代码,但是利用这些知识,您可以将异步回调排队,直到活动的 FragmentManager 在执行它们之前将其 mStateSaved 变量设置为 false。
mStateSaved 是最终负责触发此异常的变量。
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
}
所以理论上,现在您知道何时执行片段事务是安全的,因此您可以避免可怕的 IllegalStateException。
错误的!
嵌套片段
上述解决方案仅适用于 Activity 的 FragmentManager。片段本身也有一个子片段管理器,用于嵌套片段。不幸的是,子片段管理器根本不与 Activity 的片段管理器保持同步。因此,虽然活动的片段管理器是最新的并且始终具有正确的 mStateSaved;子片段不这样认为,并且会在不适当的时候愉快地抛出可怕的 IllegalStateException。
现在,如果您查看了支持库中的 Fragment.java 和 FragmentManager.java,您将不会对与 Fragment 相关的所有内容都容易出错感到惊讶。设计和代码质量……啊,值得怀疑。你喜欢布尔值吗?
mHasMenu = false
mHidden = false
mInLayout = false
mIndex = 1
mFromLayout = false
mFragmentId = 0
mLoadersStarted = true
mMenuVisible = true
mNextAnim = 0
mDetached = false
mRemoving = false
mRestored = false
mResumed = true
mRetainInstance = true
mRetaining = false
mDeferStart = false
mContainerId = 0
mState = 5
mStateAfterAnimating = 0
mCheckedForLoaderManager = true
mCalled = true
mTargetIndex = -1
mTargetRequestCode = 0
mUserVisibleHint = true
mBackStackNesting = 0
mAdded = true
总之,有点跑题了。
死胡同解决方案
因此,您可能认为问题的解决方案很简单,在这一点上似乎有点反义词,将另一个漂亮的 hacky 非 UI 片段添加到您的子片段管理器中。大概它的回调与它的内部状态是同步的,一切都会变得很花哨。
又错了!
Android 不支持作为子片段附加到其他片段(也称为嵌套片段)的保留片段实例。现在,事后看来,这应该是有道理的。如果在activity被销毁时父fragment因为没有被保留而被销毁,那么就没有地方可以重新附加子fragment了。所以这是行不通的。
我的问题
是否有人有解决方案来确定何时可以安全地对子片段执行片段事务以及异步代码回调?