试图在Android上以可靠的方式执行异步操作是不必要的麻烦,即AsyncTask确实在概念上存在缺陷吗?还是我只是缺少一些东西?
现在,一切都在引入片段之前。随着Fragments的引入,onRetainNonConfigurationInstance()已被弃用。因此,最新的Google宽容黑客手段是使用永久性的非UI片段,该片段会在配置发生变化(例如,旋转屏幕,更改语言设置等)时与您的活动相关联/分离。
范例:https:
//code.google.com/p/android/issues/detail?id =
23096#c4
从理论上讲,上面的技巧可以使您摆脱恐惧:
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。片段本身还具有子片段管理器,该子片段管理器用于嵌套片段。不幸的是,子片段管理器根本没有与活动的片段管理器保持同步。因此,尽管活动的片段管理器是最新的,并且始终具有正确的mStateSaved;子片段会另外考虑,并会在不适当的时间高兴地引发可怕的IllegalStateException。
现在,如果您在支持库中查看了Fragment.java和FragmentManager.java,那么与片段有关的所有事情都容易出错,您将不会感到惊讶。设计和代码质量是…啊,值得怀疑。你喜欢布尔吗?
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
无论如何,摆脱话题。
因此,您可能会认为问题的解决方案很简单, 这似乎有点像是反义词,
即向您的子片段管理器中添加另一个漂亮的非UI片段。大概它的回调与它的内部状态是同步的,一切都会变得花花公子。
又错了!
Android不支持将保留的片段实例作为子片段附加到其他片段(也称为嵌套片段)。现在,事后看来,这应该是有道理的。如果由于活动未保留而在活动被销毁时父片段被销毁,则无处可以重新附加子片段。所以这只是行不通的。
是否有人可以通过异步代码回调来确定何时可以安全地 对子片段 执行片段事务?
如果可以忍受,请使用React Native。我知道,我知道…“肮脏的网络技术”,但说真的,Android
SDK简直是一场灾难,所以请放下你的骄傲,随它去吧。您可能会感到惊讶;我知道我做到了!
不用担心,我建议从根本上改变您的联网方法。触发请求并运行请求处理程序以更新UI不适用于Android的组件生命周期。
而是尝试以下方法之一:
LocalBroadcastReceiver
当应用程序的本地状态更改时,具有长寿命的对象(常规Java类或Android服务)会处理您的请求并触发事件。然后在“活动/片段”中,听某些声音Intent
并相应地进行更新。我相信这是Google的最新官方解决方案。但是,该解决方案确实无法很好地扩展。如果您不习惯自己弄乱队列,处理程序和保留实例状态,那么这可能是您唯一的选择……但是请不要说我没有警告您!
Android活动和片段支持可与AsyncTaskLoader一起使用的LoaderManager。在后台,装载程序管理器的保留方式与保留的片段完全相同。因此,此解决方案与下面的我自己的解决方案确实有一些共同点。AsyncTaskLoader是一种部分罐头解决方案,在技术上可以
正常工作
。但是,API非常麻烦。我相信您会在使用它的几分钟后注意到它。
__
首先,我的解决方案绝非易事。但是,一旦实现工作顺利进行,就很容易使用,并且可以根据自己的需求对其进行自定义。
我使用保留的片段,该片段被添加到“活动”的片段管理器中(或者在我的情况下支持片段管理器)。这是我的问题中提到的相同技术。该片段充当各种 提供程序
,可跟踪其附加到的活动,并具有Message和Runnable(实际上是自定义子类)队列。当不再保存实例状态 并且
相应的处理程序(或可运行的)“准备执行” 时,将执行队列。
每个处理程序/可运行程序都存储一个引用 使用者 的UUID 。 消费者 通常是活动中某处的碎片(可以安全地嵌套)。当 使用者
片段附加到活动时,它将查找 提供者 片段并使用其UUID进行注册。
使用某种抽象(例如UUID),而不是直接引用 使用者
(即片段),这一点很重要。这是因为片段经常被破坏和重新创建,并且您希望回调具有对新片段的“引用”。不是属于被破坏活动的旧物品。因此,不幸的是,您很少可以安全地使用匿名类捕获的变量。同样,这是因为这些变量可能引用了一个已损坏的旧片段或活动。相反,你必须要求
供应商 为 消费者 处理程序已存储的UUID相匹配。然后,您可以投放此 消费者
到它实际存在的任何片段/对象并安全地使用它,因为您知道它的最新片段具有有效的Context(活动)。
当 使用者 (由UUID引用)准备就绪时,处理程序(或可运行)将“准备执行” 。除了 提供者 之外,还需要检查 使用者
是否准备就绪,因为正如我的问题中所述,即使提供者另有说明,使用者片段也可能认为其实例状态已保存。如果使用者(或提供者)尚未准备就绪,则可以将消息(或可运行)放入提供者的队列中。
__
当 使用者 片段到达onResume()时,它通知 提供者 它已准备好使用已排队的消息/可运行对象。此时, 提供者
可以尝试执行其队列中属于准备就绪的 使用者的 任何操作。
这导致处理程序始终使用有效的上下文(提供者引用的活动)和最新的有效片段(也称为“消费者”)执行。
该解决方案非常复杂,但是一旦确定了实现方法,它就可以完美地工作。如果有人提出了一个更简单的解决方案,那么我很乐意听到。
null java.lang.IllegalStateException:在onSaveInstanceState e/androidRuntime(9008):at android.support.v4.app.fragmentManagerImpl.checkStateLoss(fragmentManager.java:1354)e/androidRuntime(9008):at androi
问题内容: 我从市场上的应用程序中获取用户报告,但出现以下异常: 显然,它与FragmentManager有关,我不使用。stacktrace不显示我自己的任何类,因此我不知道发生此异常的位置以及如何防止它。 作为记录:我有一个tabhost,在每个选项卡中都有一个ActivityGroup在Activity之间切换。 问题答案: 基本上我只需要: 不要在方法上进行调用。这太糟了… 这是支持包中的
问题内容: 我是Android开发的新手。我有一个问题。我尝试了最后几个小时,但我无法弄清楚。如果是这样,我有一个很普遍的问题。IllegalStateException:使用ViewPager在onSaveInstanceState之后无法执行此操作,但由于缺少Android开发经验而失败。 这是代码: 这是错误: 位于android.os.Handler.dispatchMessage(Han
我是Android开发的新手。我有个问题。我试了几个小时,但我想不出来。如果是这样的话,我有一个很受欢迎的问题。IllegalStateException:在使用ViewPager onSaveInstanceState之后无法执行此操作,但由于缺乏Android开发经验而失败。 下面是代码:
问题内容: 嗨,我用片段A,第二个片段用b。调用了b并使用了 方法,但是我第一次使用它是完美的,但是第二次使用它使应用程序崩溃,并且我的错误日志在以下:::我使用了Samsung平板电脑,但工作正常,但是Samsung core mobile崩溃了。 我的课程用于: 使用的第二个片段: 使用的第三个片段::: 问题答案: 这被称为 状态丢失 。您碰巧从AsyncTask提交FragmentTran